diff --git a/src/Microsoft.AspNet.Abstractions/HttpRequest.cs b/src/Microsoft.AspNet.Abstractions/HttpRequest.cs
index 9e8f53a110..b4f563464b 100644
--- a/src/Microsoft.AspNet.Abstractions/HttpRequest.cs
+++ b/src/Microsoft.AspNet.Abstractions/HttpRequest.cs
@@ -83,6 +83,11 @@ namespace Microsoft.AspNet.Abstractions
/// The collection of Cookies for this request.
public abstract IReadableStringCollection Cookies { get; }
+ ///
+ /// Gets or sets the Content-Length header
+ ///
+ public abstract long? ContentLength { get; set; }
+
///
/// Gets or sets the Content-Type header.
///
diff --git a/src/Microsoft.AspNet.PipelineCore/DefaultHttpRequest.cs b/src/Microsoft.AspNet.PipelineCore/DefaultHttpRequest.cs
index 7afd73181d..9579b7c814 100644
--- a/src/Microsoft.AspNet.PipelineCore/DefaultHttpRequest.cs
+++ b/src/Microsoft.AspNet.PipelineCore/DefaultHttpRequest.cs
@@ -1,8 +1,10 @@
using System;
+using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Abstractions;
+using Microsoft.AspNet.Abstractions.Infrastructure;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.HttpFeature;
using Microsoft.AspNet.PipelineCore.Collections;
@@ -58,7 +60,6 @@ namespace Microsoft.AspNet.PipelineCore
get { return _canHasCookies.Fetch(_features) ?? _canHasCookies.Update(_features, new DefaultCanHasRequestCookies(_features)); }
}
-
public override HttpContext HttpContext { get { return _context; } }
public override PathString PathBase
@@ -79,6 +80,18 @@ namespace Microsoft.AspNet.PipelineCore
set { HttpRequestInformation.QueryString = value.Value; }
}
+ public override long? ContentLength
+ {
+ get
+ {
+ return ParsingHelpers.GetContentLength(Headers);
+ }
+ set
+ {
+ ParsingHelpers.SetContentLength(Headers, value);
+ }
+ }
+
public override Stream Body
{
get { return HttpRequestInformation.Body; }
diff --git a/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs b/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs
index 9ff8135d63..c1ec42c5d0 100644
--- a/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs
+++ b/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs
@@ -51,26 +51,11 @@ namespace Microsoft.AspNet.PipelineCore
{
get
{
- long value;
- string rawValue = Headers.Get(Constants.Headers.ContentLength);
- if (!string.IsNullOrWhiteSpace(rawValue) && long.TryParse(rawValue, out value))
- {
- return value;
- }
-
- return null;
+ return ParsingHelpers.GetContentLength(Headers);
}
set
{
- if (value.HasValue)
- {
- HttpResponseInformation.Headers[Constants.Headers.ContentLength] =
- new[] { value.Value.ToString(CultureInfo.InvariantCulture) };
- }
- else
- {
- HttpResponseInformation.Headers.Remove(Constants.Headers.ContentLength);
- }
+ ParsingHelpers.SetContentLength(Headers, value);
}
}
diff --git a/src/Microsoft.AspNet.PipelineCore/Infrastructure/ParsingHelpers.cs b/src/Microsoft.AspNet.PipelineCore/Infrastructure/ParsingHelpers.cs
index 18153db162..7ab6b1c817 100644
--- a/src/Microsoft.AspNet.PipelineCore/Infrastructure/ParsingHelpers.cs
+++ b/src/Microsoft.AspNet.PipelineCore/Infrastructure/ParsingHelpers.cs
@@ -1,8 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Abstractions;
+using Microsoft.AspNet.Abstractions.Infrastructure;
using Microsoft.AspNet.PipelineCore.Collections;
namespace Microsoft.AspNet.PipelineCore.Infrastructure
@@ -804,8 +806,8 @@ namespace Microsoft.AspNet.PipelineCore.Infrastructure
var accumulator = new Dictionary>(StringComparer.OrdinalIgnoreCase);
ParseDelimited(queryString, AmpersandAndSemicolon, AppendItemCallback, accumulator);
return accumulator.ToDictionary(
- item => item.Key,
- item => item.Value.ToArray(),
+ item => item.Key,
+ item => item.Value.ToArray(),
StringComparer.OrdinalIgnoreCase);
}
@@ -856,5 +858,31 @@ namespace Microsoft.AspNet.PipelineCore.Infrastructure
// var localPort = request.Get(OwinConstants.CommonKeys.LocalPort);
// return string.IsNullOrWhiteSpace(localPort) ? localIpAddress : (localIpAddress + ":" + localPort);
//}
+
+ public static long? GetContentLength(IHeaderDictionary headers)
+ {
+ const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
+ long value;
+ string rawValue = headers.Get(Constants.Headers.ContentLength);
+ if (!string.IsNullOrWhiteSpace(rawValue) &&
+ long.TryParse(rawValue, styles, CultureInfo.InvariantCulture, out value))
+ {
+ return value;
+ }
+
+ return null;
+ }
+
+ public static void SetContentLength(IHeaderDictionary headers, long? value)
+ {
+ if (value.HasValue)
+ {
+ headers[Constants.Headers.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ headers.Remove(Constants.Headers.ContentLength);
+ }
+ }
}
}
diff --git a/test/Microsoft.AspNet.PipelineCore.Tests/DefaultHttpRequestTests.cs b/test/Microsoft.AspNet.PipelineCore.Tests/DefaultHttpRequestTests.cs
new file mode 100644
index 0000000000..f56039abf9
--- /dev/null
+++ b/test/Microsoft.AspNet.PipelineCore.Tests/DefaultHttpRequestTests.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.AspNet.FeatureModel;
+using Microsoft.AspNet.HttpFeature;
+using Moq;
+using Xunit;
+using Xunit.Extensions;
+
+namespace Microsoft.AspNet.PipelineCore.Tests
+{
+ public class DefaultHttpRequestTests
+ {
+ [Theory]
+ [InlineData(0)]
+ [InlineData(9001)]
+ [InlineData(65535)]
+ public void GetContentLength_ReturnsParsedHeader(long value)
+ {
+ // Arrange
+ var request = GetRequest(value.ToString(CultureInfo.InvariantCulture));
+
+ // Act and Assert
+ Assert.Equal(value, request.ContentLength);
+ }
+
+ [Fact]
+ public void GetContentLength_ReturnsNullIfHeaderDoesNotExist()
+ {
+ // Arrange
+ var request = GetRequest(contentLength: null);
+
+ // Act and Assert
+ Assert.Null(request.ContentLength);
+ }
+
+ [Theory]
+ [InlineData("cant-parse-this")]
+ [InlineData("-1000")]
+ [InlineData("1000.00")]
+ [InlineData("100/5")]
+ public void GetContentLength_ReturnsNullIfHeaderCannotBeParsed(string contentLength)
+ {
+ // Arrange
+ var request = GetRequest(contentLength);
+
+ // Act and Assert
+ Assert.Null(request.ContentLength);
+ }
+
+ private static DefaultHttpRequest GetRequest(string contentLength = null)
+ {
+ var features = new Mock();
+ var mockRequestInfo = new Mock();
+ var headers = new Dictionary();
+ if (contentLength != null)
+ {
+ headers.Add("Content-Length", new[] { contentLength });
+
+ }
+ mockRequestInfo.SetupGet(r => r.Headers)
+ .Returns(headers);
+ object requestInfo = mockRequestInfo.Object;
+ features.Setup(f => f.TryGetValue(typeof(IHttpRequestInformation), out requestInfo))
+ .Returns(true);
+ var context = new DefaultHttpContext(features.Object);
+ var request = new DefaultHttpRequest(context, features.Object);
+ return request;
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.PipelineCore.Tests/project.json b/test/Microsoft.AspNet.PipelineCore.Tests/project.json
index e4bb833e89..5d77e10d07 100644
--- a/test/Microsoft.AspNet.PipelineCore.Tests/project.json
+++ b/test/Microsoft.AspNet.PipelineCore.Tests/project.json
@@ -16,6 +16,7 @@
"Microsoft.Owin.Testing": "2.1.0",
"Moq": "4.2.1312.1622",
"xunit": "1.9.2",
+ "xunit.extensions": "1.9.2",
"Microsoft.Net.Http": "2.2.13",
"System.Net.Http": ""
}