Ejemplo n.º 1
0
 /// <summary>
 /// Gets the value associated with the specified key.
 /// </summary>
 /// <param name="key">The key whose value to get.</param>
 /// <param name="value">The value associated with the specified key, if the key is found; otherwise, null.</param>
 /// <returns>true if the cache contains an element with the specified key; otherwise, false.</returns>
 public bool TryGetValue(MatchInfoCacheKey key, out MediaTypeMatchInfo value)
 {
     lock (this.dict)
     {
         return(dict.TryGetValue(key, out value));
     }
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Matches the supported media types against the list of media types specified in the Accept header or ContentType header of the message. Matching follows the
        /// rules for media type matching as described in RFC 2616.
        /// </summary>
        /// <param name="sourceTypes">The set of media types to be matched against the <paramref name="targetTypes"/>.</param>
        /// <param name="targetTypes">The set of media types the <paramref name="sourceTypes"/> will be matched against.</param>
        /// <returns>The best <see cref="MediaTypeMatchInfo"/> found during the matching process or null if no match was found.</returns>
        private static MediaTypeMatchInfo MatchMediaTypes(IEnumerable <MediaType> sourceTypes, MediaType[] targetTypes)
        {
            Debug.Assert(sourceTypes != null, "sourceTypes != null");
            Debug.Assert(targetTypes != null, "targetTypes != null");

            MediaTypeMatchInfo selectedMatchInfo = null;

            int sourceIndex = 0;

            if (sourceTypes != null)
            {
                foreach (MediaType sourceType in sourceTypes)
                {
                    int targetIndex = 0;
                    foreach (MediaType targetType in targetTypes)
                    {
                        // match the type name parts and parameters of the media type
                        MediaTypeMatchInfo currentMatchInfo = new MediaTypeMatchInfo(sourceType, targetType, sourceIndex, targetIndex);
                        if (!currentMatchInfo.IsMatch)
                        {
                            targetIndex++;
                            continue;
                        }

                        if (selectedMatchInfo == null)
                        {
                            selectedMatchInfo = currentMatchInfo;
                        }
                        else
                        {
                            int comparisonResult = selectedMatchInfo.CompareTo(currentMatchInfo);
                            if (comparisonResult < 0)
                            {
                                // If the selected match is less specific than the current match, use the current match.
                                selectedMatchInfo = currentMatchInfo;
                            }
                        }

                        targetIndex++;
                    }

                    sourceIndex++;
                }
            }

            if (selectedMatchInfo == null)
            {
                return(null);
            }

            return(selectedMatchInfo);
        }
Ejemplo n.º 3
0
        internal static ODataFormat GetContentTypeFromSettings(ODataMessageWriterSettings settings, ODataPayloadKind payloadKind, MediaTypeResolver mediaTypeResolver, out MediaType mediaType, out Encoding encoding)
        {
            ODataFormat         format;
            MediaTypeWithFormat format2;

            MediaTypeWithFormat[] mediaTypesForPayloadKind = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);
            if ((mediaTypesForPayloadKind == null) || (mediaTypesForPayloadKind.Length == 0))
            {
                throw new ODataContentTypeException(Microsoft.Data.OData.Strings.MediaTypeUtils_DidNotFindMatchingMediaType(null, settings.AcceptableMediaTypes));
            }
            if (settings.UseFormat == true)
            {
                mediaType = GetDefaultMediaType(mediaTypesForPayloadKind, settings.Format, out format);
                encoding  = mediaType.SelectEncoding();
                return(format);
            }
            IList <KeyValuePair <MediaType, string> > specifiedTypes = HttpUtils.MediaTypesFromString(settings.AcceptableMediaTypes);

            if (((ODataVersion)settings.Version) == ODataVersion.V3)
            {
                specifiedTypes = RemoveApplicationJsonFromAcceptableMediaTypes(specifiedTypes, mediaTypesForPayloadKind, settings.AcceptableMediaTypes);
            }
            string str = null;

            if ((specifiedTypes == null) || (specifiedTypes.Count == 0))
            {
                format2 = mediaTypesForPayloadKind[0];
            }
            else
            {
                MediaTypeMatchInfo info = MatchMediaTypes(from kvp in specifiedTypes select kvp.Key, (from smt in mediaTypesForPayloadKind select smt.MediaType).ToArray <MediaType>());
                if (info == null)
                {
                    throw new ODataContentTypeException(Microsoft.Data.OData.Strings.MediaTypeUtils_DidNotFindMatchingMediaType(string.Join(", ", (from mt in mediaTypesForPayloadKind select mt.MediaType.ToText()).ToArray <string>()), settings.AcceptableMediaTypes));
                }
                format2 = mediaTypesForPayloadKind[info.TargetTypeIndex];
                KeyValuePair <MediaType, string> pair = specifiedTypes[info.SourceTypeIndex];
                str = pair.Value;
            }
            format    = format2.Format;
            mediaType = format2.MediaType;
            string acceptableCharsets = settings.AcceptableCharsets;

            if (str != null)
            {
                acceptableCharsets = (acceptableCharsets == null) ? str : (str + "," + acceptableCharsets);
            }
            encoding = GetEncoding(acceptableCharsets, payloadKind, mediaType, true);
            return(format);
        }
Ejemplo n.º 4
0
            /// <summary>
            /// Adds an element with the provided key and value to the cache.
            /// </summary>
            /// <param name="key">The key of the element to add.</param>
            /// <param name="value">The value of the element to add.</param>
            public void Add(MatchInfoCacheKey key, MediaTypeMatchInfo value)
            {
                lock (this.dict)
                {
                    if (!dict.ContainsKey(key))
                    {
                        if (dict.Count == maxSize)
                        {
                            dict.Clear();
                        }

                        dict.Add(key, value);
                    }
                }
            }
Ejemplo n.º 5
0
        /// <summary>
        /// Determine the <see cref="ODataFormat"/> to use for the given <paramref name="contentTypeName"/>. If no supported content type
        /// is found an exception is thrown.
        /// </summary>
        /// <param name="contentTypeName">The name of the content type to be checked.</param>
        /// <param name="supportedPayloadKinds">All possiblel kinds of payload that can be read with this content type.</param>
        /// <param name="mediaTypeResolver">The media type resolver to use when interpreting the content type.</param>
        /// <param name="mediaType">The media type parsed from the <paramref name="contentTypeName"/>.</param>
        /// <param name="encoding">The encoding from the content type or the default encoding for the <paramref name="mediaType" />.</param>
        /// <param name="selectedPayloadKind">
        /// The payload kind that was selected form the list of <paramref name="supportedPayloadKinds"/> for the
        /// specified <paramref name="contentTypeName"/>.
        /// </param>
        /// <returns>The <see cref="ODataFormat"/> for the <paramref name="contentTypeName"/>.</returns>
        private static ODataFormat GetFormatFromContentType(
            string contentTypeName,
            ODataPayloadKind[] supportedPayloadKinds,
            MediaTypeResolver mediaTypeResolver,
            out MediaType mediaType,
            out Encoding encoding,
            out ODataPayloadKind selectedPayloadKind)
        {
            Debug.Assert(!supportedPayloadKinds.Contains(ODataPayloadKind.Unsupported), "!supportedPayloadKinds.Contains(ODataPayloadKind.Unsupported)");

            string charset;

            mediaType = ParseContentType(contentTypeName, out charset);

            // Special code to handle unsupported media types that cannot be caught by conneg
            // since they are sub-types of valid media types (i.e., application/json;odata=light would
            // match application/json).
            // NOTE: once we start supporting Json Light we have to make this check version-aware.
            FailOnUnsupportedMediaTypes(mediaType, contentTypeName, supportedPayloadKinds, mediaTypeResolver);

            MediaTypeWithFormat[] supportedMediaTypes = null;
            for (int i = 0; i < supportedPayloadKinds.Length; ++i)
            {
                // get the supported and default media types for the current payload kind
                ODataPayloadKind supportedPayloadKind = supportedPayloadKinds[i];
                supportedMediaTypes = mediaTypeResolver.GetMediaTypesForPayloadKind(supportedPayloadKind);

                // match the specified media types against the supported/default ones
                // and get the format
                MediaTypeMatchInfo matchInfo = MatchMediaTypes(supportedMediaTypes.Select(smt => smt.MediaType), new MediaType[] { mediaType });
                if (matchInfo != null)
                {
                    Debug.Assert(matchInfo.TargetTypeIndex == 0, "Invalid target type index detected.");
                    selectedPayloadKind = supportedPayloadKind;
                    encoding            = GetEncoding(charset, selectedPayloadKind, mediaType, /*useDefaultEncoding*/ false);
                    return(supportedMediaTypes[matchInfo.SourceTypeIndex].Format);
                }
            }

            // We're calling the ToArray here since not all platforms support the string.Join which takes IEnumerable.
            Debug.Assert(supportedMediaTypes != null, "supportedMediaTypes != null");
            string supportedTypesAsString = string.Join(", ", supportedPayloadKinds.SelectMany(pk => mediaTypeResolver.GetMediaTypesForPayloadKind(pk).Select(mt => mt.MediaType.ToText())).ToArray());

            throw new ODataContentTypeException(Strings.MediaTypeUtils_CannotDetermineFormatFromContentType(supportedTypesAsString, contentTypeName));
        }
Ejemplo n.º 6
0
        internal static IList <ODataPayloadKindDetectionResult> GetPayloadKindsForContentType(string contentTypeHeader, MediaTypeResolver mediaTypeResolver, out MediaType contentType)
        {
            string str;

            contentType = ParseContentType(contentTypeHeader, out str);
            MediaType[] targetTypes = new MediaType[] { contentType };
            List <ODataPayloadKindDetectionResult> list = new List <ODataPayloadKindDetectionResult>();

            MediaTypeWithFormat[] mediaTypesForPayloadKind = null;
            for (int i = 0; i < allSupportedPayloadKinds.Length; i++)
            {
                ODataPayloadKind payloadKind = allSupportedPayloadKinds[i];
                mediaTypesForPayloadKind = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);
                MediaTypeMatchInfo info = MatchMediaTypes(from smt in mediaTypesForPayloadKind select smt.MediaType, targetTypes);
                if (info != null)
                {
                    list.Add(new ODataPayloadKindDetectionResult(payloadKind, mediaTypesForPayloadKind[info.SourceTypeIndex].Format));
                }
            }
            return(list);
        }
Ejemplo n.º 7
0
        private static ODataFormat GetFormatFromContentType(string contentTypeName, ODataPayloadKind[] supportedPayloadKinds, MediaTypeResolver mediaTypeResolver, out MediaType mediaType, out Encoding encoding, out ODataPayloadKind selectedPayloadKind)
        {
            string str;

            mediaType = ParseContentType(contentTypeName, out str);
            FailOnUnsupportedMediaTypes(mediaType, contentTypeName, supportedPayloadKinds, mediaTypeResolver);
            MediaTypeWithFormat[] mediaTypesForPayloadKind = null;
            for (int i = 0; i < supportedPayloadKinds.Length; i++)
            {
                ODataPayloadKind payloadKind = supportedPayloadKinds[i];
                mediaTypesForPayloadKind = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);
                MediaTypeMatchInfo info = MatchMediaTypes(from smt in mediaTypesForPayloadKind select smt.MediaType, new MediaType[] { mediaType });
                if (info != null)
                {
                    selectedPayloadKind = payloadKind;
                    encoding            = GetEncoding(str, selectedPayloadKind, mediaType, false);
                    return(mediaTypesForPayloadKind[info.SourceTypeIndex].Format);
                }
            }
            throw new ODataContentTypeException(Microsoft.Data.OData.Strings.MediaTypeUtils_CannotDetermineFormatFromContentType(string.Join(", ", (from pk in supportedPayloadKinds select from mt in mediaTypeResolver.GetMediaTypesForPayloadKind(pk) select mt.MediaType.ToText()).SelectMany(x => x).ToArray <string>()), contentTypeName));
        }
Ejemplo n.º 8
0
        private static MediaTypeMatchInfo MatchMediaTypes(IEnumerable <MediaType> sourceTypes, MediaType[] targetTypes)
        {
            MediaTypeMatchInfo info = null;
            int sourceIndex         = 0;

            if (sourceTypes != null)
            {
                foreach (MediaType type in sourceTypes)
                {
                    int targetIndex = 0;
                    foreach (MediaType type2 in targetTypes)
                    {
                        MediaTypeMatchInfo other = new MediaTypeMatchInfo(type, type2, sourceIndex, targetIndex);
                        if (!other.IsMatch)
                        {
                            targetIndex++;
                        }
                        else
                        {
                            if (info == null)
                            {
                                info = other;
                            }
                            else if (info.CompareTo(other) < 0)
                            {
                                info = other;
                            }
                            targetIndex++;
                        }
                    }
                    sourceIndex++;
                }
            }
            if (info == null)
            {
                return(null);
            }
            return(info);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Gets all payload kinds and their corresponding formats that match the specified content type header.
        /// </summary>
        /// <param name="contentTypeHeader">The content type header to get the payload kinds for.</param>
        /// <param name="mediaTypeResolver">The media type resolver to use when interpreting the content type.</param>
        /// <param name="contentType">The parsed content type as <see cref="MediaType"/>.</param>
        /// <param name="encoding">The encoding from the content type or the default encoding from <see cref="MediaType" />.</param>
        /// <returns>The list of payload kinds and formats supported for the specified <paramref name="contentTypeHeader"/>.</returns>
        internal static IList <ODataPayloadKindDetectionResult> GetPayloadKindsForContentType(string contentTypeHeader, MediaTypeResolver mediaTypeResolver, out MediaType contentType, out Encoding encoding)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(!String.IsNullOrEmpty(contentTypeHeader), "Content-Type header must not be null or empty.");

            string charset;

            encoding    = null;
            contentType = ParseContentType(contentTypeHeader, out charset);
            MediaType[] targetTypes = new MediaType[] { contentType };

            List <ODataPayloadKindDetectionResult> payloadKinds = new List <ODataPayloadKindDetectionResult>();

            IList <MediaTypeWithFormat> mediaTypesForKind = null;

            for (int i = 0; i < allSupportedPayloadKinds.Length; ++i)
            {
                // get the supported and default media types for the current payload kind
                ODataPayloadKind payloadKind = allSupportedPayloadKinds[i];
                mediaTypesForKind = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);

                // match the specified media types against the supported/default ones
                // and get the format
                MediaTypeMatchInfo matchInfo = MatchMediaTypes(mediaTypesForKind.Select(smt => smt.MediaType), targetTypes);
                if (matchInfo != null)
                {
                    Debug.Assert(matchInfo.TargetTypeIndex == 0, "Invalid target type index detected.");
                    payloadKinds.Add(new ODataPayloadKindDetectionResult(payloadKind, mediaTypesForKind[matchInfo.SourceTypeIndex].Format));
                }
            }

            if (!String.IsNullOrEmpty(charset))
            {
                encoding = HttpUtils.GetEncodingFromCharsetName(charset);
            }

            return(payloadKinds);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Given the Accept and the Accept-Charset headers of the request message computes the media type, encoding and <see cref="ODataFormat"/>
        /// to be used for the response message.
        /// </summary>
        /// <param name="settings">The message writer settings to use for serializing the response payload.</param>
        /// <param name="payloadKind">The kind of payload to be serialized as part of the response message.</param>
        /// <param name="mediaTypeResolver">The media type resolver to use when interpreting the content type.</param>
        /// <param name="mediaType">The media type to be used in the response message.</param>
        /// <param name="encoding">The encoding to be used in the response message.</param>
        /// <returns>The <see cref="ODataFormat"/> used when serializing the response.</returns>
        internal static ODataFormat GetContentTypeFromSettings(
            ODataMessageWriterSettings settings,
            ODataPayloadKind payloadKind,
            MediaTypeResolver mediaTypeResolver,
            out MediaType mediaType,
            out Encoding encoding)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(settings != null, "settings != null");

            // compute format, media type and encoding
            ODataFormat format;

            // get the supported and default media types for the specified payload kind
            MediaTypeWithFormat[] supportedMediaTypes = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);
            if (supportedMediaTypes == null || supportedMediaTypes.Length == 0)
            {
                throw new ODataContentTypeException(Strings.MediaTypeUtils_DidNotFindMatchingMediaType(null, settings.AcceptableMediaTypes));
            }

            if (settings.UseFormat == true)
            {
                Debug.Assert(settings.AcceptableMediaTypes == null, "settings.AcceptableMediaTypes == null");
                Debug.Assert(settings.AcceptableCharsets == null, "settings.AcceptableCharsets == null");

                mediaType = GetDefaultMediaType(supportedMediaTypes, settings.Format, out format);

                // NOTE the default media types don't have any parameters (in particular no 'charset' parameters)
                encoding = mediaType.SelectEncoding();
            }
            else
            {
                // parse the accept header into its parts
                IList <KeyValuePair <MediaType, string> > specifiedTypes = HttpUtils.MediaTypesFromString(settings.AcceptableMediaTypes);

                if (settings.Version == ODataVersion.V3)
                {
                    specifiedTypes = RemoveApplicationJsonFromAcceptableMediaTypes(specifiedTypes, supportedMediaTypes, settings.AcceptableMediaTypes);
                }

                MediaTypeWithFormat selectedMediaTypeWithFormat;
                string specifiedCharset = null;
                if (specifiedTypes == null || specifiedTypes.Count == 0)
                {
                    selectedMediaTypeWithFormat = supportedMediaTypes[0];
                }
                else
                {
                    // match the specified media types against the supported/default ones and get the format
                    MediaTypeMatchInfo matchInfo = MatchMediaTypes(specifiedTypes.Select(kvp => kvp.Key), supportedMediaTypes.Select(smt => smt.MediaType).ToArray());
                    if (matchInfo == null)
                    {
                        // We're calling the ToArray here since not all platforms support the string.Join which takes IEnumerable.
                        string supportedTypesAsString = string.Join(", ", supportedMediaTypes.Select(mt => mt.MediaType.ToText()).ToArray());
                        throw new ODataContentTypeException(Strings.MediaTypeUtils_DidNotFindMatchingMediaType(supportedTypesAsString, settings.AcceptableMediaTypes));
                    }

                    selectedMediaTypeWithFormat = supportedMediaTypes[matchInfo.TargetTypeIndex];
                    specifiedCharset            = specifiedTypes[matchInfo.SourceTypeIndex].Value;
                }

                format    = selectedMediaTypeWithFormat.Format;
                mediaType = selectedMediaTypeWithFormat.MediaType;

                // If a charset was specified with the accept header, consider it for the encoding
                string acceptableCharsets = settings.AcceptableCharsets;
                if (specifiedCharset != null)
                {
                    acceptableCharsets = acceptableCharsets == null ? specifiedCharset : specifiedCharset + "," + acceptableCharsets;
                }

                encoding = GetEncoding(acceptableCharsets, payloadKind, mediaType, /*useDefaultEncoding*/ true);
            }

            return(format);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Given the Accept and the Accept-Charset headers of the request message computes the media type, encoding and <see cref="ODataFormat"/>
        /// to be used for the response message.
        /// </summary>
        /// <param name="settings">The message writer settings to use for serializing the response payload.</param>
        /// <param name="payloadKind">The kind of payload to be serialized as part of the response message.</param>
        /// <param name="mediaTypeResolver">The media type resolver to use when interpreting the content type.</param>
        /// <param name="mediaType">The media type to be used in the response message.</param>
        /// <param name="encoding">The encoding to be used in the response message.</param>
        /// <returns>The <see cref="ODataFormat"/> used when serializing the response.</returns>
        internal static ODataFormat GetContentTypeFromSettings(
            ODataMessageWriterSettings settings,
            ODataPayloadKind payloadKind,
            MediaTypeResolver mediaTypeResolver,
            out MediaType mediaType,
            out Encoding encoding)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(settings != null, "settings != null");

            // compute format, media type and encoding
            ODataFormat format;

            // get the supported and default media types for the specified payload kind
            IList <MediaTypeWithFormat> supportedMediaTypes = mediaTypeResolver.GetMediaTypesForPayloadKind(payloadKind);

            if (supportedMediaTypes == null || supportedMediaTypes.Count == 0)
            {
                throw new ODataContentTypeException(Strings.MediaTypeUtils_DidNotFindMatchingMediaType(null, settings.AcceptableMediaTypes));
            }

            if (settings.UseFormat == true)
            {
                Debug.Assert(settings.AcceptableMediaTypes == null, "settings.AcceptableMediaTypes == null");
                Debug.Assert(settings.AcceptableCharsets == null, "settings.AcceptableCharsets == null");

                mediaType = GetDefaultMediaType(supportedMediaTypes, settings.Format, out format);

                // NOTE the default media types don't have any parameters (in particular no 'charset' parameters)
                encoding = mediaType.SelectEncoding();
            }
            else
            {
                // parse the accept header into its parts
                IList <KeyValuePair <MediaType, string> > specifiedTypes = HttpUtils.MediaTypesFromString(settings.AcceptableMediaTypes);

                // Starting in V3 we replace all occurrences of application/json with application/json;odata=minimalmetadata
                // before handing the acceptable media types to the conneg code. This is necessary because for an accept
                // header 'application/json, application/json;odata=verbose' we want to the result to be 'application/json;odata=minimalmetadata'
                // although this is not compliant with the default conneg rules (where application/json;odata=verbose would win).
                if (settings.Version >= ODataVersion.V3)
                {
                    ConvertApplicationJsonInAcceptableMediaTypes(specifiedTypes);
                }

                MediaTypeWithFormat selectedMediaTypeWithFormat;
                string specifiedCharset = null;
                if (specifiedTypes == null || specifiedTypes.Count == 0)
                {
                    selectedMediaTypeWithFormat = supportedMediaTypes[0];
                }
                else
                {
                    // match the specified media types against the supported/default ones and get the format
                    MediaTypeMatchInfo matchInfo = MatchMediaTypes(specifiedTypes.Select(kvp => kvp.Key), supportedMediaTypes.Select(smt => smt.MediaType).ToArray());
                    if (matchInfo == null)
                    {
                        // We're calling the ToArray here since not all platforms support the string.Join which takes IEnumerable.
                        string supportedTypesAsString = String.Join(", ", supportedMediaTypes.Select(mt => mt.MediaType.ToText()).ToArray());
                        throw new ODataContentTypeException(Strings.MediaTypeUtils_DidNotFindMatchingMediaType(supportedTypesAsString, settings.AcceptableMediaTypes));
                    }

                    selectedMediaTypeWithFormat = supportedMediaTypes[matchInfo.TargetTypeIndex];
                    specifiedCharset            = specifiedTypes[matchInfo.SourceTypeIndex].Value;
                }

                format    = selectedMediaTypeWithFormat.Format;
                mediaType = selectedMediaTypeWithFormat.MediaType;

                // If a charset was specified with the accept header, consider it for the encoding
                string acceptableCharsets = settings.AcceptableCharsets;
                if (specifiedCharset != null)
                {
                    acceptableCharsets = acceptableCharsets == null ? specifiedCharset : specifiedCharset + "," + acceptableCharsets;
                }

                encoding = GetEncoding(acceptableCharsets, payloadKind, mediaType, /*useDefaultEncoding*/ true);
            }

            return(format);
        }