Exemplo n.º 1
0
 /// <summary>
 /// Determines whether the media type has a 'IEEE754Compatible' parameter with the value 'true'.
 /// </summary>
 /// <param name="mediaType">The media type to check</param>
 /// <returns>
 ///   <c>true</c> if  the media type has a 'IEEE754Compatible' parameter with the value 'true'; otherwise, <c>false</c>.
 /// </returns>
 internal static bool HasIeee754CompatibleSetToTrue(this ODataMediaType mediaType)
 {
     return(mediaType.MediaTypeHasParameterWithValue(MimeConstants.MimeIeee754CompatibleParameterName, MimeConstants.MimeParameterValueTrue));
 }
Exemplo n.º 2
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="ODataMediaType"/>.</param>
        /// <param name="encoding">The encoding from the content type or the default encoding from <see cref="ODataMediaType" />.</param>
        /// <returns>The list of payload kinds and formats supported for the specified <paramref name="contentTypeHeader"/>.</returns>
        internal static IList <ODataPayloadKindDetectionResult> GetPayloadKindsForContentType(string contentTypeHeader, ODataMediaTypeResolver mediaTypeResolver, out ODataMediaType contentType, out Encoding encoding)
        {
            Debug.Assert(!String.IsNullOrEmpty(contentTypeHeader), "Content-Type header must not be null or empty.");

            string charset;

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

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

            IList <ODataMediaTypeFormat> 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.GetMediaTypeFormats(payloadKind).ToList();

                // 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);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Determines whether the media type has a 'streaming' parameter with the value 'true'.
 /// </summary>
 /// <param name="mediaType">The media type to check.</param>
 /// <returns>
 ///   <c>true</c> if  the media type has a 'streaming' parameter with the value 'true'; otherwise, <c>false</c>.
 /// </returns>
 internal static bool HasStreamingSetToTrue(this ODataMediaType mediaType)
 {
     return(mediaType.MediaTypeHasParameterWithValue(MimeConstants.MimeStreamingParameterName, MimeConstants.MimeParameterValueTrue));
 }
Exemplo n.º 4
0
        /// <summary>
        /// Detects the payload kind(s) from the message stream.
        /// </summary>
        /// <param name="contentType">The content type of the message.</param>
        /// <returns>An enumerable of zero, one or more payload kinds that were detected from looking at the payload in the message stream.</returns>
        private static IEnumerable <ODataPayloadKind> DetectPayloadKindImplementation(ODataMediaType contentType)
        {
            Debug.Assert(contentType != null, "contentType != null");

            if (HttpUtils.CompareMediaTypeNames(MimeConstants.MimeTextType, contentType.Type) &&
                HttpUtils.CompareMediaTypeNames(MimeConstants.MimeTextPlain, contentType.SubType))
            {
                return(new ODataPayloadKind[] { ODataPayloadKind.Value });
            }

            return(new ODataPayloadKind[] { ODataPayloadKind.BinaryValue });
        }
Exemplo n.º 5
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,
            ODataMediaTypeResolver mediaTypeResolver,
            out ODataMediaType mediaType,
            out Encoding encoding)
        {
            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 <ODataMediaTypeFormat> supportedMediaTypes = mediaTypeResolver.GetMediaTypeFormats(payloadKind).ToList();

            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 <ODataMediaType, string> > specifiedTypes = HttpUtils.MediaTypesFromString(settings.AcceptableMediaTypes);

                // Starting in V3 we replace all occurrences of application/json with application/json;odata.metadata=minimal
                // before handing the acceptable media types to the conneg code. This is necessary because for an accept
                // header 'application/json, we want to the result to be 'application/json;odata.metadata=minimal'
                ConvertApplicationJsonInAcceptableMediaTypes(specifiedTypes);

                ODataMediaTypeFormat 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);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Configure the media type tables so that Json Light is the first JSON format in the table, except for the
        /// case of Batch payload kind, where the JsonLight media types is added to the back of the list to preserve
        /// original behavior of default MIME media type.
        /// </summary>
        /// <remarks>
        /// This is only used in V4 and beyond.
        /// </remarks>
        private void AddJsonLightMediaTypes()
        {
            var optionalParameters = new[]
            {
                new
                {
                    ParameterName = MimeConstants.MimeMetadataParameterName,
                    Values        = new[] { MimeConstants.MimeMetadataParameterValueMinimal, MimeConstants.MimeMetadataParameterValueFull, MimeConstants.MimeMetadataParameterValueNone }
                },
                new
                {
                    ParameterName = MimeConstants.MimeStreamingParameterName,
                    Values        = new[] { MimeConstants.MimeParameterValueTrue, MimeConstants.MimeParameterValueFalse }
                },
                new
                {
                    ParameterName = MimeConstants.MimeIeee754CompatibleParameterName,
                    Values        = new[] { MimeConstants.MimeParameterValueFalse, MimeConstants.MimeParameterValueTrue }
                },
            };

            // initial seed for the list will be extended in breadth-first passes over the optional parameters
            var mediaTypesToAdd = new LinkedList <ODataMediaType>();

            mediaTypesToAdd.AddFirst(ApplicationJsonMediaType);

            foreach (var optionalParameter in optionalParameters)
            {
                // go through each one so far and extend it
                for (LinkedListNode <ODataMediaType> currentNode = mediaTypesToAdd.First; currentNode != null; currentNode = currentNode.Next)
                {
                    ODataMediaType typeToExtend = currentNode.Value;
                    foreach (string valueToAdd in optionalParameter.Values)
                    {
                        var extendedParameters = new List <KeyValuePair <string, string> >(typeToExtend.Parameters ?? Enumerable.Empty <KeyValuePair <string, string> >())
                        {
                            new KeyValuePair <string, string>(optionalParameter.ParameterName, valueToAdd)
                        };

                        var extendedMediaType = new ODataMediaType(typeToExtend.Type, typeToExtend.SubType, extendedParameters);

                        // always match more specific things first
                        mediaTypesToAdd.AddBefore(currentNode, extendedMediaType);
                    }
                }
            }

            List <ODataMediaTypeFormat> mediaTypeWithFormat = mediaTypesToAdd.Select(mediaType => new ODataMediaTypeFormat(mediaType, ODataFormat.Json)).ToList();

            foreach (ODataPayloadKind kind in JsonPayloadKinds)
            {
                if (kind == ODataPayloadKind.Batch)
                {
                    // Appending the json media types AFTER the existing MIME media type(s), which is the default media type for Batch payload kind.
                    this.mediaTypesForPayloadKind[(int)kind].AddRange(mediaTypeWithFormat);
                }
                else
                {   // For other payload kinds, insert the json media types to the front.
                    this.mediaTypesForPayloadKind[(int)kind].InsertRange(0, mediaTypeWithFormat);
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>Builds a Content-Type header which includes media type and encoding information.</summary>
        /// <param name="mediaType">Media type to be used.</param>
        /// <param name="encoding">Encoding to be used in response, possibly null.</param>
        /// <returns>The value for the Content-Type header.</returns>
        internal static string BuildContentType(ODataMediaType mediaType, Encoding encoding)
        {
            Debug.Assert(mediaType != null, "mediaType != null");

            return(mediaType.ToText(encoding));
        }
Exemplo n.º 8
0
        /// <summary>Gets the best encoding available for the specified charset request.</summary>
        /// <param name="acceptableCharsets">
        /// The Accept-Charset header value (eg: "iso-8859-5, unicode-1-1;q=0.8").
        /// </param>
        /// <param name="mediaType">The media type used to compute the default encoding for the payload.</param>
        /// <param name="utf8Encoding">The encoding to use for UTF-8 charsets; we use the one without the BOM.</param>
        /// <param name="defaultEncoding">The encoding to use if no encoding could be computed from the <paramref name="acceptableCharsets"/> or <paramref name="mediaType"/>.</param>
        /// <returns>An Encoding object appropriate to the specified charset request.</returns>
        internal static Encoding EncodingFromAcceptableCharsets(string acceptableCharsets, ODataMediaType mediaType, Encoding utf8Encoding, Encoding defaultEncoding)
        {
            Debug.Assert(mediaType != null, "mediaType != null");

            // 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(acceptableCharsets))
            {
                // PERF: in the future if we find that computing the encoding from the accept charsets is
                //       too expensive we could introduce a cache of original strings to resolved encoding.
                CharsetPart[] parts = new List <CharsetPart>(AcceptCharsetParts(acceptableCharsets)).ToArray();

                // NOTE: List<T>.Sort uses an unstable sort algorithm; if charsets have the same quality value
                //       we want to pick the first one specified so we need a stable sort.
                KeyValuePair <int, CharsetPart>[] sortedParts = parts.StableSort(delegate(CharsetPart x, CharsetPart y)
                {
                    return(y.Quality - x.Quality);
                });

                foreach (KeyValuePair <int, CharsetPart> sortedPart in sortedParts)
                {
                    CharsetPart part = sortedPart.Value;
                    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 = utf8Encoding;
                            break;
                        }
                        else
                        {
                            result = GetEncodingFromCharsetName(part.Charset);
                            if (result != null)
                            {
                                break;
                            }

                            // If the charset is not supported it is ignored so other possible charsets are evaluated.
                        }
                    }
                }
            }

            // No Charset was specified, or if charsets were specified, no valid charset was found.
            // Returning a different charset is also valid. Get the default encoding for the media type.
            if (result == null)
            {
                result = mediaType.SelectEncoding();
                if (result == null)
                {
                    return(defaultEncoding);
                }
            }

            return(result);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Append default values required by OData to specified HTTP header.
        ///
        /// When header name is ODataConstants.ContentTypeHeader, if header value is application/json
        ///     append the following default values for 4.0:
        ///         odata.metadata=minimal
        ///         odata.streaming=true
        ///         IEEE754Compatible=false
        ///     append the following default values for 4.01:
        ///         metadata=minimal
        ///         streaming=true
        ///         IEEE754Compatible=false
        /// </summary>
        /// <param name="headerName">The name of the header to append default values.</param>
        /// <param name="headerValue">The original header value string.</param>
        /// <param name="version">The ODataVersion for which to create the default header value</param>
        /// <returns>The header value string with appended default values.</returns>
        public static string AppendDefaultHeaderValue(string headerName, string headerValue, ODataVersion version)
        {
            if (string.CompareOrdinal(headerName, ODataConstants.ContentTypeHeader) != 0)
            {
                return(headerValue);
            }

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

            var mediaTypeList = HttpUtils.MediaTypesFromString(headerValue);
            var mediaType     = mediaTypeList.Single().Key;
            var encoding      = HttpUtils.GetEncodingFromCharsetName(mediaTypeList.Single().Value);

            if (string.CompareOrdinal(mediaType.FullTypeName, MimeConstants.MimeApplicationJson) != 0)
            {
                return(headerValue);
            }

            var extendedParameters = new List <KeyValuePair <string, string> >();
            var extendedMediaType  = new ODataMediaType(mediaType.Type, mediaType.SubType, extendedParameters);

            var hasMetadata          = false;
            var hasStreaming         = false;
            var hasIeee754Compatible = false;

            if (mediaType.Parameters != null)
            {
                foreach (var parameter in mediaType.Parameters)
                {
                    extendedParameters.Add(parameter);

                    if (HttpUtils.IsMetadataParameter(parameter.Key))
                    {
                        hasMetadata = true;
                    }

                    if (HttpUtils.IsStreamingParameter(parameter.Key))
                    {
                        hasStreaming = true;
                    }

                    if (string.Compare(parameter.Key, MimeConstants.MimeIeee754CompatibleParameterName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        hasIeee754Compatible = true;
                    }
                }
            }

            if (!hasMetadata)
            {
                extendedParameters.Add(new KeyValuePair <string, string>(
                                           version < ODataVersion.V401 ? MimeConstants.MimeMetadataParameterName : MimeConstants.MimeShortMetadataParameterName,
                                           MimeConstants.MimeMetadataParameterValueMinimal));
            }

            if (!hasStreaming)
            {
                extendedParameters.Add(new KeyValuePair <string, string>(
                                           version < ODataVersion.V401 ? MimeConstants.MimeStreamingParameterName : MimeConstants.MimeShortStreamingParameterName,
                                           MimeConstants.MimeParameterValueTrue));
            }

            if (!hasIeee754Compatible)
            {
                extendedParameters.Add(new KeyValuePair <string, string>(
                                           MimeConstants.MimeIeee754CompatibleParameterName,
                                           MimeConstants.MimeParameterValueFalse));
            }

            return(extendedMediaType.ToText(encoding));
        }
Exemplo n.º 10
0
 /// <summary>
 /// Returns the appropriate content-type for this format.
 /// </summary>
 /// <param name="mediaType">The specified media type.</param>
 /// <param name="encoding">The specified encoding.</param>
 /// <param name="writingResponse">True if the message writer is being used to write a response.</param>
 /// <param name="mediaTypeParameters"> The resultant parameters list of the media type. Parameters list could be updated
 /// when getting content type and should be returned if that is the case.
 /// </param>
 /// <returns>The content-type value for the format.</returns>
 internal virtual string GetContentType(ODataMediaType mediaType, Encoding encoding,
                                        bool writingResponse, out IEnumerable <KeyValuePair <string, string> > mediaTypeParameters)
 {
     mediaTypeParameters = mediaType.Parameters;
     return(HttpUtils.BuildContentType(mediaType, encoding));
 }