Skip to content

Commit 9ac0a8c

Browse files
committed
Adding ContentLength to HttpRequest
Partially addresses #15
1 parent 2dfdfaf commit 9ac0a8c

File tree

6 files changed

+122
-20
lines changed

6 files changed

+122
-20
lines changed

src/Microsoft.AspNet.Abstractions/HttpRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ public abstract class HttpRequest
8383
/// <returns>The collection of Cookies for this request.</returns>
8484
public abstract IReadableStringCollection Cookies { get; }
8585

86+
/// <summary>
87+
/// Gets or sets the Content-Length header
88+
/// </summary>
89+
public abstract long? ContentLength { get; set; }
90+
8691
/// <summary>
8792
/// Gets or sets the Content-Type header.
8893
/// </summary>

src/Microsoft.AspNet.PipelineCore/DefaultHttpRequest.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
2+
using System.Globalization;
23
using System.IO;
34
using System.Threading;
45
using System.Threading.Tasks;
56
using Microsoft.AspNet.Abstractions;
7+
using Microsoft.AspNet.Abstractions.Infrastructure;
68
using Microsoft.AspNet.FeatureModel;
79
using Microsoft.AspNet.HttpFeature;
810
using Microsoft.AspNet.PipelineCore.Collections;
@@ -58,7 +60,6 @@ private ICanHasRequestCookies CanHasRequestCookies
5860
get { return _canHasCookies.Fetch(_features) ?? _canHasCookies.Update(_features, new DefaultCanHasRequestCookies(_features)); }
5961
}
6062

61-
6263
public override HttpContext HttpContext { get { return _context; } }
6364

6465
public override PathString PathBase
@@ -79,6 +80,18 @@ public override QueryString QueryString
7980
set { HttpRequestInformation.QueryString = value.Value; }
8081
}
8182

83+
public override long? ContentLength
84+
{
85+
get
86+
{
87+
return ParsingHelpers.GetContentLength(Headers);
88+
}
89+
set
90+
{
91+
ParsingHelpers.SetContentLength(Headers, value);
92+
}
93+
}
94+
8295
public override Stream Body
8396
{
8497
get { return HttpRequestInformation.Body; }

src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,11 @@ public override long? ContentLength
5151
{
5252
get
5353
{
54-
long value;
55-
string rawValue = Headers.Get(Constants.Headers.ContentLength);
56-
if (!string.IsNullOrWhiteSpace(rawValue) && long.TryParse(rawValue, out value))
57-
{
58-
return value;
59-
}
60-
61-
return null;
54+
return ParsingHelpers.GetContentLength(Headers);
6255
}
6356
set
6457
{
65-
if (value.HasValue)
66-
{
67-
HttpResponseInformation.Headers[Constants.Headers.ContentLength] =
68-
new[] { value.Value.ToString(CultureInfo.InvariantCulture) };
69-
}
70-
else
71-
{
72-
HttpResponseInformation.Headers.Remove(Constants.Headers.ContentLength);
73-
}
58+
ParsingHelpers.SetContentLength(Headers, value);
7459
}
7560
}
7661

src/Microsoft.AspNet.PipelineCore/Infrastructure/ParsingHelpers.cs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4+
using System.Globalization;
45
using System.Linq;
56
using Microsoft.AspNet.Abstractions;
7+
using Microsoft.AspNet.Abstractions.Infrastructure;
68
using Microsoft.AspNet.PipelineCore.Collections;
79

810
namespace Microsoft.AspNet.PipelineCore.Infrastructure
@@ -804,8 +806,8 @@ internal static IDictionary<string, string[]> GetQuery(string queryString)
804806
var accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
805807
ParseDelimited(queryString, AmpersandAndSemicolon, AppendItemCallback, accumulator);
806808
return accumulator.ToDictionary(
807-
item => item.Key,
808-
item => item.Value.ToArray(),
809+
item => item.Key,
810+
item => item.Value.ToArray(),
809811
StringComparer.OrdinalIgnoreCase);
810812
}
811813

@@ -856,5 +858,31 @@ internal static partial class ParsingHelpers
856858
// var localPort = request.Get<string>(OwinConstants.CommonKeys.LocalPort);
857859
// return string.IsNullOrWhiteSpace(localPort) ? localIpAddress : (localIpAddress + ":" + localPort);
858860
//}
861+
862+
public static long? GetContentLength(IHeaderDictionary headers)
863+
{
864+
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
865+
long value;
866+
string rawValue = headers.Get(Constants.Headers.ContentLength);
867+
if (!string.IsNullOrWhiteSpace(rawValue) &&
868+
long.TryParse(rawValue, styles, CultureInfo.InvariantCulture, out value))
869+
{
870+
return value;
871+
}
872+
873+
return null;
874+
}
875+
876+
public static void SetContentLength(IHeaderDictionary headers, long? value)
877+
{
878+
if (value.HasValue)
879+
{
880+
headers[Constants.Headers.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture);
881+
}
882+
else
883+
{
884+
headers.Remove(Constants.Headers.ContentLength);
885+
}
886+
}
859887
}
860888
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Collections.Generic;
2+
using System.Globalization;
3+
using Microsoft.AspNet.FeatureModel;
4+
using Microsoft.AspNet.HttpFeature;
5+
using Moq;
6+
using Xunit;
7+
using Xunit.Extensions;
8+
9+
namespace Microsoft.AspNet.PipelineCore.Tests
10+
{
11+
public class DefaultHttpRequestTests
12+
{
13+
[Theory]
14+
[InlineData(0)]
15+
[InlineData(9001)]
16+
[InlineData(65535)]
17+
public void GetContentLength_ReturnsParsedHeader(long value)
18+
{
19+
// Arrange
20+
var request = GetRequest(value.ToString(CultureInfo.InvariantCulture));
21+
22+
// Act and Assert
23+
Assert.Equal(value, request.ContentLength);
24+
}
25+
26+
[Fact]
27+
public void GetContentLength_ReturnsNullIfHeaderDoesNotExist()
28+
{
29+
// Arrange
30+
var request = GetRequest(contentLength: null);
31+
32+
// Act and Assert
33+
Assert.Null(request.ContentLength);
34+
}
35+
36+
[Theory]
37+
[InlineData("cant-parse-this")]
38+
[InlineData("-1000")]
39+
[InlineData("1000.00")]
40+
[InlineData("100/5")]
41+
public void GetContentLength_ReturnsNullIfHeaderCannotBeParsed(string contentLength)
42+
{
43+
// Arrange
44+
var request = GetRequest(contentLength);
45+
46+
// Act and Assert
47+
Assert.Null(request.ContentLength);
48+
}
49+
50+
private static DefaultHttpRequest GetRequest(string contentLength = null)
51+
{
52+
var features = new Mock<IFeatureCollection>();
53+
var mockRequestInfo = new Mock<IHttpRequestInformation>();
54+
var headers = new Dictionary<string, string[]>();
55+
if (contentLength != null)
56+
{
57+
headers.Add("Content-Length", new[] { contentLength });
58+
59+
}
60+
mockRequestInfo.SetupGet(r => r.Headers)
61+
.Returns(headers);
62+
object requestInfo = mockRequestInfo.Object;
63+
features.Setup(f => f.TryGetValue(typeof(IHttpRequestInformation), out requestInfo))
64+
.Returns(true);
65+
var context = new DefaultHttpContext(features.Object);
66+
var request = new DefaultHttpRequest(context, features.Object);
67+
return request;
68+
}
69+
}
70+
}

test/Microsoft.AspNet.PipelineCore.Tests/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"Microsoft.Owin.Testing": "2.1.0",
1717
"Moq": "4.2.1312.1622",
1818
"xunit": "1.9.2",
19+
"xunit.extensions": "1.9.2",
1920
"Microsoft.Net.Http": "2.2.13",
2021
"System.Net.Http": ""
2122
}

0 commit comments

Comments
 (0)