Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

[Perf] Add ContentLength to IHeaderDictionary #757

Merged
merged 1 commit into from
Jan 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Microsoft.AspNetCore.Http.Features/IHeaderDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ public interface IHeaderDictionary : IDictionary<string, StringValues>
/// <param name="key"></param>
/// <returns>The stored value, or StringValues.Empty if the key is not present.</returns>
new StringValues this[string key] { get; set; }

/// <summary>
/// Strongly typed access to the Content-Length header. Implementations must keep this in sync with the string representation.
/// </summary>
long? ContentLength { get; set; }
}
}
14 changes: 14 additions & 0 deletions src/Microsoft.AspNetCore.Http.Features/exceptions.net45.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"OldTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewMemberId": "System.Nullable<System.Int64> get_ContentLength()",
"Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewMemberId": "System.Void set_ContentLength(System.Nullable<System.Int64> value)",
"Kind": "Addition"
}
]
14 changes: 14 additions & 0 deletions src/Microsoft.AspNetCore.Http.Features/exceptions.netcore.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"OldTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewMemberId": "System.Nullable<System.Int64> get_ContentLength()",
"Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewTypeId": "public interface Microsoft.AspNetCore.Http.IHeaderDictionary : System.Collections.Generic.IDictionary<System.String, Microsoft.Extensions.Primitives.StringValues>",
"NewMemberId": "System.Void set_ContentLength(System.Nullable<System.Int64> value)",
"Kind": "Addition"
}
]
29 changes: 29 additions & 0 deletions src/Microsoft.AspNetCore.Http/HeaderDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections;
using System.Collections.Generic;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Http
{
Expand Down Expand Up @@ -97,6 +98,34 @@ StringValues IDictionary<string, StringValues>.this[string key]
set { this[key] = value; }
}

public long? ContentLength
{
get
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like duplication here and in DictionaryStringValuesWrapper. Should we keep this in a helper method like before and just call it from the getter and setter of the ContentLength properties.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it but the implementation is actually different, their internal stores work a little differently.

{
long value;
var rawValue = this[HeaderNames.ContentLength];
Copy link
Contributor

@JunTaoLuo JunTaoLuo Jan 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the value in the string is being parsed every time from the string? Don't we want to store this as a long somewhere that's being kept in sync with the value stored in the string dictionary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the same as before. Kestrel and WebListener will provide more optimized versions of IHeaderDictionary. I didn't optimize this one because it's primarily used in tests.

Copy link
Contributor

@JunTaoLuo JunTaoLuo Jan 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I should have read your first comment more carefully before looking at the code.

if (rawValue.Count == 1 &&
!string.IsNullOrWhiteSpace(rawValue[0]) &&
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
{
return value;
}

return null;
}
set
{
if (value.HasValue)
{
this[HeaderNames.ContentLength] = HeaderUtilities.FormatInt64(value.Value);
}
else
{
this.Remove(HeaderNames.ContentLength);
}
}
}

/// <summary>
/// Gets the number of elements contained in the <see cref="HeaderDictionary" />;.
/// </summary>
Expand Down
10 changes: 2 additions & 8 deletions src/Microsoft.AspNetCore.Http/Internal/DefaultHttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,8 @@ public override QueryString QueryString

public override long? ContentLength
{
get
{
return ParsingHelpers.GetContentLength(Headers);
}
set
{
ParsingHelpers.SetContentLength(Headers, value);
}
get { return Headers.ContentLength; }
set { Headers.ContentLength = value; }
}

public override Stream Body
Expand Down
10 changes: 2 additions & 8 deletions src/Microsoft.AspNetCore.Http/Internal/DefaultHttpResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,8 @@ public override Stream Body

public override long? ContentLength
{
get
{
return ParsingHelpers.GetContentLength(Headers);
}
set
{
ParsingHelpers.SetContentLength(Headers, value);
}
get { return Headers.ContentLength; }
set { Headers.ContentLength = value; }
}

public override string ContentType
Expand Down
36 changes: 0 additions & 36 deletions src/Microsoft.AspNetCore.Http/Internal/ParsingHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,41 +403,5 @@ private static string DeQuote(string value)

return value;
}

public static long? GetContentLength(IHeaderDictionary headers)
{
if (headers == null)
{
throw new ArgumentNullException(nameof(headers));
}

long value;
var rawValue = headers[HeaderNames.ContentLength];
if (rawValue.Count == 1 &&
!string.IsNullOrWhiteSpace(rawValue[0]) &&
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
{
return value;
}

return null;
}

public static void SetContentLength(IHeaderDictionary headers, long? value)
{
if (headers == null)
{
throw new ArgumentNullException(nameof(headers));
}

if (value.HasValue)
{
headers[HeaderNames.ContentLength] = HeaderUtilities.FormatInt64(value.Value);
}
else
{
headers.Remove(HeaderNames.ContentLength);
}
}
}
}
35 changes: 35 additions & 0 deletions src/Microsoft.AspNetCore.Owin/DictionaryStringValuesWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Owin
{
Expand Down Expand Up @@ -42,6 +43,40 @@ StringValues IDictionary<string, StringValues>.this[string key]
set { Inner[key] = value; }
}

public long? ContentLength
{
get
{
long value;

string[] rawValue;
if (!Inner.TryGetValue(HeaderNames.ContentLength, out rawValue))
{
return null;
}

if (rawValue.Length == 1 &&
!string.IsNullOrWhiteSpace(rawValue[0]) &&
HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
{
return value;
}

return null;
}
set
{
if (value.HasValue)
{
Inner[HeaderNames.ContentLength] = (StringValues)HeaderUtilities.FormatInt64(value.Value);
}
else
{
Inner.Remove(HeaderNames.ContentLength);
}
}
}

int ICollection<KeyValuePair<string, StringValues>>.Count => Inner.Count;

bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => Inner.IsReadOnly;
Expand Down