Add utilities methods for working with MIME
Suggestions for alternative naming would be welcome, but we do want these to be public. Signed-off-by: Jon Skeet <jonskeet@google.com>
This commit is contained in:
parent
89044ec905
commit
951a8c5c42
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2021 Cloud Native Foundation.
|
||||
// Licensed under the Apache 2.0 license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
|
||||
namespace CloudNative.CloudEvents
|
||||
{
|
||||
// TODO: Consider this name and namespace carefully. It really does need to be public, as all the event formatters are elsewhere.
|
||||
// But it's not ideal...
|
||||
|
||||
/// <summary>
|
||||
/// Utility and extension methods around MIME.
|
||||
/// </summary>
|
||||
public static class MimeUtilities
|
||||
{
|
||||
// TODO: Should we return null, and force the caller to do the appropriate defaulting?
|
||||
/// <summary>
|
||||
/// Returns an encoding from a content type, defaulting to UTF-8.
|
||||
/// </summary>
|
||||
/// <param name="contentType">The content type, or null if no content type is known.</param>
|
||||
/// <returns>An encoding suitable for the charset specified in <paramref name="contentType"/>,
|
||||
/// or UTF-8 if no charset has been specified.</returns>
|
||||
public static Encoding GetEncoding(this ContentType contentType) =>
|
||||
contentType?.CharSet is string charSet ? Encoding.GetEncoding(charSet) : Encoding.UTF8;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="MediaTypeHeaderValue"/> into a <see cref="ContentType"/>.
|
||||
/// </summary>
|
||||
/// <param name="headerValue">The header value to convert. May be null.</param>
|
||||
/// <returns>The converted content type, or null if <paramref name="headerValue"/> is null.</returns>
|
||||
public static ContentType ToContentType(this MediaTypeHeaderValue headerValue) =>
|
||||
headerValue is null ? null : new ContentType(headerValue.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ContentType"/> into a <see cref="MediaTypeHeaderValue"/>.
|
||||
/// </summary>
|
||||
/// <param name="contentType">The content type to convert. May be null.</param>
|
||||
/// <returns>The converted media type header value, or null if <paramref name="contentType"/> is null.</returns>
|
||||
public static MediaTypeHeaderValue ToMediaTypeHeaderValue(this ContentType contentType)
|
||||
{
|
||||
if (contentType is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var header = new MediaTypeHeaderValue(contentType.MediaType);
|
||||
foreach (string parameterName in contentType.Parameters.Keys)
|
||||
{
|
||||
header.Parameters.Add(new NameValueHeaderValue(parameterName, contentType.Parameters[parameterName].ToString()));
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ContentType"/> from the given value, or returns null
|
||||
/// if the input is null.
|
||||
/// </summary>
|
||||
/// <param name="contentType">The content type textual value. May be null.</param>
|
||||
/// <returns>The converted content type, or null if <paramref name="contentType"/> is null.</returns>
|
||||
public static ContentType CreateContentTypeOrNull(string contentType) =>
|
||||
contentType is null ? null : new ContentType(contentType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2021 Cloud Native Foundation.
|
||||
// Licensed under the Apache 2.0 license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace CloudNative.CloudEvents.UnitTests.Http
|
||||
{
|
||||
public class MimeUtilitiesTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("application/json; charset=iso-8859-1")]
|
||||
[InlineData("application/json; charset=iso-8859-1; name=some-name")]
|
||||
[InlineData("application/json; charset=iso-8859-1; name=some-name; x=y; a=b")]
|
||||
[InlineData("application/json; charset=iso-8859-1; name=some-name; boundary=xyzzy; x=y")]
|
||||
public void ContentTypeConversions(string text)
|
||||
{
|
||||
var originalContentType = new ContentType(text);
|
||||
var header = originalContentType.ToMediaTypeHeaderValue();
|
||||
AssertEqualParts(text, header.ToString());
|
||||
var convertedContentType = header.ToContentType();
|
||||
AssertEqualParts(originalContentType.ToString(), convertedContentType.ToString());
|
||||
|
||||
// Conversions can end up reordering the parameters. In reality we're only
|
||||
// likely to end up with a media type and charset, but our tests use more parameters.
|
||||
// This just makes them deterministic.
|
||||
void AssertEqualParts(string expected, string actual)
|
||||
{
|
||||
expected = string.Join(";", expected.Split(";").OrderBy(x => x));
|
||||
actual = string.Join(";", actual.Split(";").OrderBy(x => x));
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentTypeConversions_Null()
|
||||
{
|
||||
Assert.Null(default(ContentType).ToMediaTypeHeaderValue());
|
||||
Assert.Null(default(MediaTypeHeaderValue).ToContentType());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("iso-8859-1")]
|
||||
[InlineData("utf-8")]
|
||||
public void ContentTypeGetEncoding(string charSet)
|
||||
{
|
||||
var contentType = new ContentType($"text/plain; charset={charSet}");
|
||||
Encoding encoding = contentType.GetEncoding();
|
||||
Assert.Equal(charSet, encoding.WebName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentTypeGetEncoding_NoContentType()
|
||||
{
|
||||
ContentType contentType = null;
|
||||
Encoding encoding = contentType.GetEncoding();
|
||||
Assert.Equal(Encoding.UTF8, encoding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentTypeGetEncoding_NoCharSet()
|
||||
{
|
||||
ContentType contentType = new ContentType("text/plain");
|
||||
Encoding encoding = contentType.GetEncoding();
|
||||
Assert.Equal(Encoding.UTF8, encoding);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("text/plain")]
|
||||
public void CreateContentTypeOrNull_WithContentType(string text)
|
||||
{
|
||||
ContentType ct = MimeUtilities.CreateContentTypeOrNull(text);
|
||||
Assert.Equal(text, ct?.ToString());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue