Skip to content

Commit

Permalink
Avoid a few allocations in StringContent
Browse files Browse the repository at this point in the history
  • Loading branch information
MihaZupan committed Jun 3, 2024
1 parent aedb91f commit b7fb7ab
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.IO;
using System.Net.Http.Headers;
using System.Text;
Expand Down Expand Up @@ -45,8 +46,31 @@ public StringContent(string content, Encoding? encoding)
/// <param name="encoding">The encoding to use for the content.</param>
/// <param name="mediaType">The media type to use for the content.</param>
public StringContent(string content, Encoding? encoding, string mediaType)
: this(content, encoding, new MediaTypeHeaderValue(mediaType ?? DefaultMediaType, (encoding ?? DefaultStringEncoding).WebName))
: base(GetContentByteArray(content, encoding))
{
Debug.Assert(DefaultStringEncoding.WebName == "utf-8");

encoding ??= DefaultStringEncoding;
mediaType ??= DefaultMediaType;

// Avoid allocating MediaTypeHeaderValue and related objects for common media types.
if (ReferenceEquals(encoding, DefaultStringEncoding))
{
string? knownValue = mediaType switch
{
"text/plain" => "text/plain; charset=utf-8",
"application/json" => "application/json; charset=utf-8",
_ => null
};

if (knownValue is not null)
{
Headers.TryAddWithoutValidation(KnownHeaders.ContentType.Descriptor, knownValue);
return;
}
}

Headers.ContentType = new MediaTypeHeaderValue(mediaType, encoding.WebName);
}

/// <summary>Creates a new instance of the <see cref="StringContent"/> class.</summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net.Http.Headers;
using System.Text;
using Xunit;

namespace System.Net.Http.Tests
{
public class StringContentTests
{
[Fact]
public void StringContent_SetsDefaultContentTypeHeader()
{
var content = new StringContent("Foo");
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", (Encoding)null);
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", Encoding.UTF8);
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", Encoding.UTF8, "text/plain");
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", null, "text/plain");
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", Encoding.UTF8, (string)null);
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", null, (string)null);
Assert.Equal("text/plain; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("Foo", (MediaTypeHeaderValue)null);
Assert.Null(content.Headers.ContentType);

content = new StringContent("Foo", null, (MediaTypeHeaderValue)null);
Assert.Null(content.Headers.ContentType);
}

[Theory]
[InlineData("text/plain")]
[InlineData("application/json")]
[InlineData("application/xml")]
[InlineData("foo/bar")]
public void StringContent_SetsContentTypeHeader(string mediaType)
{
var content = new StringContent("foo", Encoding.UTF8, mediaType);
Assert.Equal($"{mediaType}; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("foo", null, mediaType);
Assert.Equal($"{mediaType}; charset=utf-8", content.Headers.ContentType.ToString());

content = new StringContent("foo", Encoding.ASCII, mediaType);
Assert.Equal($"{mediaType}; charset=us-ascii", content.Headers.ContentType.ToString());

content = new StringContent("foo", new MediaTypeHeaderValue(mediaType));
Assert.Equal(mediaType, content.Headers.ContentType.ToString());

content = new StringContent("foo", Encoding.UTF8, new MediaTypeHeaderValue(mediaType, "ascii"));
Assert.Equal($"{mediaType}; charset=ascii", content.Headers.ContentType.ToString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@
<Compile Include="MockContent.cs" />
<Compile Include="RuntimeSettingParserTest.cs" />
<Compile Include="StreamToStreamCopyTest.cs" />
<Compile Include="StringContentTests.cs" />
<Compile Include="HttpEnvironmentProxyTest.cs" />
<Compile Include="HttpRequestExceptionTests.cs" />
<Compile Include="HttpWindowsProxyTest.cs" />
Expand Down

0 comments on commit b7fb7ab

Please sign in to comment.