/// <summary> /// Parses the specified content type header into a media type instance. /// </summary> /// <param name="contentTypeHeader">The content type header to parse.</param> /// <param name="charset">The optional charset specified with the content type.</param> /// <returns>The <see cref="ODataMediaType"/> of the parsed <paramref name="contentTypeHeader"/>.</returns> private static ODataMediaType ParseContentType(string contentTypeHeader, out string charset) { Debug.Assert(!String.IsNullOrEmpty(contentTypeHeader), "!string.IsNullOrEmpty(contentTypeHeader)"); // parse the content type header into its parts, make sure we only allow one content type to be specified. IList <KeyValuePair <ODataMediaType, string> > specifiedTypes = HttpUtils.MediaTypesFromString(contentTypeHeader); if (specifiedTypes.Count != 1) { throw new ODataContentTypeException(Strings.MediaTypeUtils_NoOrMoreThanOneContentTypeSpecified(contentTypeHeader)); } ODataMediaType contentType = specifiedTypes[0].Key; CheckMediaTypeForWildCards(contentType); charset = specifiedTypes[0].Value; return(contentType); }
/// <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)); }
/// <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); }