diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs
index f63599a..fd1dd9d 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs
@@ -72,7 +72,7 @@ internal FeatureContext(RequestContext requestContext, bool enableResponseCachin
_enableResponseCaching = enableResponseCaching;
// Pre-initialize any fields that are not lazy at the lower level.
- _requestHeaders = new HeaderDictionary(Request.Headers);
+ _requestHeaders = Request.Headers;
_httpMethod = Request.Method;
_path = Request.Path;
_pathBase = Request.PathBase;
@@ -82,7 +82,7 @@ internal FeatureContext(RequestContext requestContext, bool enableResponseCachin
_user = _requestContext.User;
_responseStream = new ResponseStream(requestContext.Response.Body, OnStart);
- _responseHeaders = new HeaderDictionary(Response.Headers);
+ _responseHeaders = Response.Headers;
}
internal IFeatureCollection Features => _features;
diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs
deleted file mode 100644
index fdc00ee..0000000
--- a/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Primitives;
-
-namespace Microsoft.AspNetCore.Server.HttpSys
-{
- ///
- /// Represents a wrapper for RequestHeaders and ResponseHeaders.
- ///
- internal class HeaderDictionary : IHeaderDictionary
- {
- public HeaderDictionary(IDictionary store)
- {
- Store = store;
- }
-
- private IDictionary Store { get; set; }
-
- ///
- /// Get or sets the associated value from the collection as a single string.
- ///
- /// The header name.
- /// the associated value from the collection as a StringValues or StringValues.Empty if the key is not present.
- public StringValues this[string key]
- {
- get
- {
- StringValues value;
- if (TryGetValue(key, out value))
- {
- return value;
- }
- return StringValues.Empty;
- }
- set
- {
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- if (StringValues.IsNullOrEmpty(value))
- {
- Store.Remove(key);
- }
- else
- {
- Store[key] = value;
- }
- }
- }
-
- ///
- /// Throws KeyNotFoundException if the key is not present.
- ///
- /// The header name.
- ///
- StringValues IDictionary.this[string key]
- {
- get { return Store[key]; }
- set { this[key] = value; }
- }
-
- ///
- /// Gets the number of elements contained in the ;.
- ///
- /// The number of elements contained in the .
- public int Count
- {
- get { return Store.Count; }
- }
-
- ///
- /// Gets a value that indicates whether the is in read-only mode.
- ///
- /// true if the is in read-only mode; otherwise, false.
- public bool IsReadOnly
- {
- get { return Store.IsReadOnly; }
- }
-
- public ICollection Keys
- {
- get { return Store.Keys; }
- }
-
- public ICollection Values
- {
- get { return Store.Values; }
- }
-
- ///
- /// Adds a new list of items to the collection.
- ///
- /// The item to add.
- public void Add(KeyValuePair item)
- {
- Store.Add(item.Key, item.Value);
- }
-
- ///
- /// Adds the given header and values to the collection.
- ///
- /// The header name.
- /// The header values.
- public void Add(string key, StringValues value)
- {
- Store.Add(key, value);
- }
-
- ///
- /// Clears the entire list of objects.
- ///
- public void Clear()
- {
- Store.Clear();
- }
-
- ///
- /// Returns a value indicating whether the specified object occurs within this collection.
- ///
- /// The item.
- /// true if the specified object occurs within this collection; otherwise, false.
- public bool Contains(KeyValuePair item)
- {
- return Store.Contains(item);
- }
-
- ///
- /// Determines whether the contains a specific key.
- ///
- /// The key.
- /// true if the contains a specific key; otherwise, false.
- public bool ContainsKey(string key)
- {
- return Store.ContainsKey(key);
- }
-
- ///
- /// Copies the elements to a one-dimensional Array instance at the specified index.
- ///
- /// The one-dimensional Array that is the destination of the specified objects copied from
- /// the .
- /// The zero-based index in at which copying begins.
- public void CopyTo(KeyValuePair[] array, int arrayIndex)
- {
- Store.CopyTo(array, arrayIndex);
- }
-
- ///
- /// Removes the given item from the the collection.
- ///
- /// The item.
- /// true if the specified object was removed from the collection; otherwise, false.
- public bool Remove(KeyValuePair item)
- {
- return Store.Remove(item);
- }
-
- ///
- /// Removes the given header from the collection.
- ///
- /// The header name.
- /// true if the specified object was removed from the collection; otherwise, false.
- public bool Remove(string key)
- {
- return Store.Remove(key);
- }
-
- ///
- /// Retrieves a value from the dictionary.
- ///
- /// The header name.
- /// The value.
- /// true if the contains the key; otherwise, false.
- public bool TryGetValue(string key, out StringValues value)
- {
- return Store.TryGetValue(key, out value);
- }
-
- ///
- /// Returns an enumerator that iterates through a collection.
- ///
- /// An object that can be used to iterate through the collection.
- public IEnumerator GetEnumerator()
- {
- return Store.GetEnumerator();
- }
-
- ///
- /// Returns an enumerator that iterates through a collection.
- ///
- /// An object that can be used to iterate through the collection.
- IEnumerator> IEnumerable>.GetEnumerator()
- {
- return Store.GetEnumerator();
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs
index 4f6cd22..1eef943 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs
@@ -4,12 +4,17 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.HttpSys
{
- internal class HeaderCollection : IDictionary
+ internal class HeaderCollection : IHeaderDictionary
{
+ private long? _contentLength;
+ private StringValues _contentLengthText;
+
public HeaderCollection()
: this(new Dictionary(4, StringComparer.OrdinalIgnoreCase))
{
@@ -75,6 +80,52 @@ public ICollection Values
get { return Store.Values; }
}
+ public long? ContentLength
+ {
+ get
+ {
+ long value;
+ var rawValue = this[HttpKnownHeaderNames.ContentLength];
+
+ if (_contentLengthText.Equals(rawValue))
+ {
+ return _contentLength;
+ }
+
+ if (rawValue.Count == 1 &&
+ !string.IsNullOrWhiteSpace(rawValue[0]) &&
+ HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value))
+ {
+ _contentLengthText = rawValue;
+ _contentLength = value;
+ return value;
+ }
+
+ return null;
+ }
+ set
+ {
+ ThrowIfReadOnly();
+
+ if (value.HasValue)
+ {
+ if (value.Value < 0)
+ {
+ throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative.");
+ }
+ _contentLengthText = HeaderUtilities.FormatInt64(value.Value);
+ this[HttpKnownHeaderNames.ContentLength] = _contentLengthText;
+ _contentLength = value;
+ }
+ else
+ {
+ Remove(HttpKnownHeaderNames.ContentLength);
+ _contentLengthText = StringValues.Empty;
+ _contentLength = null;
+ }
+ }
+ }
+
public void Add(KeyValuePair item)
{
ThrowIfReadOnly();
diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs
index d9f0958..31846b6 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs
@@ -147,48 +147,8 @@ internal long ExpectedBodyLength
// Header accessors
public long? ContentLength
{
- get
- {
- string contentLengthString = Headers[HttpKnownHeaderNames.ContentLength];
- long contentLength;
- if (!string.IsNullOrWhiteSpace(contentLengthString))
- {
- contentLengthString = contentLengthString.Trim();
- if (string.Equals(Constants.Zero, contentLengthString, StringComparison.Ordinal))
- {
- return 0;
- }
- else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength))
- {
- return contentLength;
- }
- }
- return null;
- }
- set
- {
- CheckResponseStarted();
- if (!value.HasValue)
- {
- Headers.Remove(HttpKnownHeaderNames.ContentLength);
- }
- else
- {
- if (value.Value < 0)
- {
- throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative.");
- }
-
- if (value.Value == 0)
- {
- Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero;
- }
- else
- {
- Headers[HttpKnownHeaderNames.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture);
- }
- }
- }
+ get { return Headers.ContentLength; }
+ set { Headers.ContentLength = value; }
}
///
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
index bb4688e..1e79dff 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
@@ -83,7 +83,7 @@ public async Task Request_FieldsCanBeSet_Set()
Assert.Equal("TEST", requestInfo.Method);
requestInfo.Body = new MemoryStream();
Assert.IsType(requestInfo.Body);
- var customHeaders = new HeaderDictionary(new HeaderCollection());
+ var customHeaders = new HeaderCollection();
requestInfo.Headers = customHeaders;
Assert.Same(customHeaders, requestInfo.Headers);
requestInfo.Scheme = "abcd";