From f050e09283be468998a7bcb7868beea7a484aff2 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 4 Nov 2015 16:03:36 -0800 Subject: [PATCH] Revert use of explicit converters that prevent APIs from returning null. --- .../HeaderDictionaryExtensions.cs | 2 +- .../HeaderDictionaryTypeExtensions.cs | 4 +- .../Internal/ParsingHelpers.cs | 2 +- .../RequestHeaders.cs | 2 +- .../ResponseHeaders.cs | 2 +- .../DefaultHttpRequest.cs | 2 +- .../DefaultHttpResponse.cs | 2 +- .../DefaultWebSocketManager.cs | 2 +- .../Features/FormFile.cs | 4 +- .../RequestCookieCollection.cs | 6 +- .../MultipartReader.cs | 2 +- .../MultipartSection.cs | 4 +- .../DefaultHttpRequestTests.cs | 2 + .../DefaultHttpResponseTests.cs | 90 +++++++++++++++++++ 14 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 test/Microsoft.AspNet.Http.Tests/DefaultHttpResponseTests.cs diff --git a/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryExtensions.cs b/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryExtensions.cs index fedf74ab..6a8d909d 100644 --- a/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryExtensions.cs +++ b/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryExtensions.cs @@ -36,7 +36,7 @@ public static void AppendCommaSeparatedValues(this IHeaderDictionary headers, st /// the associated values from the collection separated into individual values, or StringValues.Empty if the key is not present. public static string[] GetCommaSeparatedValues(this IHeaderDictionary headers, string key) { - return ParsingHelpers.GetHeaderSplit(headers, key).ToArray(); + return ParsingHelpers.GetHeaderSplit(headers, key); } /// diff --git a/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryTypeExtensions.cs b/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryTypeExtensions.cs index c9ac784d..cd8d26ca 100644 --- a/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryTypeExtensions.cs +++ b/src/Microsoft.AspNet.Http.Extensions/HeaderDictionaryTypeExtensions.cs @@ -179,7 +179,7 @@ internal static T Get(this IHeaderDictionary headers, string name) if (KnownParsers.TryGetValue(typeof(T), out temp)) { var func = (Func)temp; - return func(headers[name].ToString()); + return func(headers[name]); } var value = headers[name]; @@ -202,7 +202,7 @@ internal static IList GetList(this IHeaderDictionary headers, string name) if (KnownListParsers.TryGetValue(typeof(T), out temp)) { var func = (Func, IList>)temp; - return func(headers[name].ToArray()); + return func(headers[name]); } var values = headers[name]; diff --git a/src/Microsoft.AspNet.Http.Extensions/Internal/ParsingHelpers.cs b/src/Microsoft.AspNet.Http.Extensions/Internal/ParsingHelpers.cs index 8d1e5f83..78b7fcd7 100644 --- a/src/Microsoft.AspNet.Http.Extensions/Internal/ParsingHelpers.cs +++ b/src/Microsoft.AspNet.Http.Extensions/Internal/ParsingHelpers.cs @@ -126,7 +126,7 @@ public static void AppendHeaderJoined(IHeaderDictionary headers, string key, par return; } - string existing = GetHeader(headers, key).ToString(); + string existing = GetHeader(headers, key); if (existing == null) { SetHeaderJoined(headers, key, values); diff --git a/src/Microsoft.AspNet.Http.Extensions/RequestHeaders.cs b/src/Microsoft.AspNet.Http.Extensions/RequestHeaders.cs index 800c0def..dbfff554 100644 --- a/src/Microsoft.AspNet.Http.Extensions/RequestHeaders.cs +++ b/src/Microsoft.AspNet.Http.Extensions/RequestHeaders.cs @@ -170,7 +170,7 @@ public HostString Host { get { - return HostString.FromUriComponent(Headers[HeaderNames.Host].ToString()); + return HostString.FromUriComponent(Headers[HeaderNames.Host]); } set { diff --git a/src/Microsoft.AspNet.Http.Extensions/ResponseHeaders.cs b/src/Microsoft.AspNet.Http.Extensions/ResponseHeaders.cs index baad250f..931b2d93 100644 --- a/src/Microsoft.AspNet.Http.Extensions/ResponseHeaders.cs +++ b/src/Microsoft.AspNet.Http.Extensions/ResponseHeaders.cs @@ -134,7 +134,7 @@ public Uri Location get { Uri uri; - if (Uri.TryCreate(Headers[HeaderNames.Location].ToString(), UriKind.RelativeOrAbsolute, out uri)) + if (Uri.TryCreate(Headers[HeaderNames.Location], UriKind.RelativeOrAbsolute, out uri)) { return uri; } diff --git a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs index c39f01cb..d11e75bc 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs @@ -140,7 +140,7 @@ public override bool IsHttps public override HostString Host { - get { return HostString.FromUriComponent(Headers["Host"].ToString()); } + get { return HostString.FromUriComponent(Headers["Host"]); } set { Headers["Host"] = value.ToUriComponent(); } } diff --git a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs index 3eade210..f239261b 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs @@ -87,7 +87,7 @@ public override string ContentType { get { - return Headers[HeaderNames.ContentType].ToString(); + return Headers[HeaderNames.ContentType]; } set { diff --git a/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs b/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs index e7394a53..454b0fa6 100644 --- a/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs +++ b/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs @@ -55,7 +55,7 @@ public override IList WebSocketRequestedProtocols { get { - return ParsingHelpers.GetHeaderSplit(HttpRequestFeature.Headers, HeaderNames.WebSocketSubProtocols).ToArray(); + return ParsingHelpers.GetHeaderSplit(HttpRequestFeature.Headers, HeaderNames.WebSocketSubProtocols); } } diff --git a/src/Microsoft.AspNet.Http/Features/FormFile.cs b/src/Microsoft.AspNet.Http/Features/FormFile.cs index d803cd21..557dc9d5 100644 --- a/src/Microsoft.AspNet.Http/Features/FormFile.cs +++ b/src/Microsoft.AspNet.Http/Features/FormFile.cs @@ -21,13 +21,13 @@ public FormFile(Stream baseStream, long baseStreamOffset, long length) public string ContentDisposition { - get { return Headers["Content-Disposition"].ToString(); } + get { return Headers["Content-Disposition"]; } set { Headers["Content-Disposition"] = value; } } public string ContentType { - get { return Headers["Content-Type"].ToString(); } + get { return Headers["Content-Type"]; } set { Headers["Content-Type"] = value; } } diff --git a/src/Microsoft.AspNet.Http/RequestCookieCollection.cs b/src/Microsoft.AspNet.Http/RequestCookieCollection.cs index 363b69df..8b2a4423 100644 --- a/src/Microsoft.AspNet.Http/RequestCookieCollection.cs +++ b/src/Microsoft.AspNet.Http/RequestCookieCollection.cs @@ -48,7 +48,7 @@ public string this[string key] if (Store == null) { - return string.Empty; + return null; } string value; @@ -56,7 +56,7 @@ public string this[string key] { return value; } - return string.Empty; + return null; } } @@ -126,7 +126,7 @@ public bool TryGetValue(string key, out string value) { if (Store == null) { - value = string.Empty; + value = null; return false; } return Store.TryGetValue(key, out value); diff --git a/src/Microsoft.AspNet.WebUtilities/MultipartReader.cs b/src/Microsoft.AspNet.WebUtilities/MultipartReader.cs index e9e0aba9..2af2a444 100644 --- a/src/Microsoft.AspNet.WebUtilities/MultipartReader.cs +++ b/src/Microsoft.AspNet.WebUtilities/MultipartReader.cs @@ -87,7 +87,7 @@ private async Task> ReadHeadersAsync(Cancellati throw new InvalidOperationException("Total header size limit exceeded: " + TotalHeaderSizeLimit.ToString()); } int splitIndex = line.IndexOf(':'); - Debug.Assert(splitIndex > 0, $"Invalid header line: {line.ToString()}"); + Debug.Assert(splitIndex > 0, $"Invalid header line: {line}"); if (splitIndex >= 0) { var name = line.Substring(0, splitIndex); diff --git a/src/Microsoft.AspNet.WebUtilities/MultipartSection.cs b/src/Microsoft.AspNet.WebUtilities/MultipartSection.cs index f3a6e5cc..196cf424 100644 --- a/src/Microsoft.AspNet.WebUtilities/MultipartSection.cs +++ b/src/Microsoft.AspNet.WebUtilities/MultipartSection.cs @@ -16,7 +16,7 @@ public string ContentType StringValues values; if (Headers.TryGetValue("Content-Type", out values)) { - return values.ToString(); + return values; } return null; } @@ -29,7 +29,7 @@ public string ContentDisposition StringValues values; if (Headers.TryGetValue("Content-Disposition", out values)) { - return values.ToString(); + return values; } return null; } diff --git a/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs b/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs index 586b8ca1..6defe395 100644 --- a/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs +++ b/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs @@ -169,6 +169,8 @@ public void Cookies_GetAndSet() Assert.Equal(0, cookieHeaders.Count); var cookies0 = request.Cookies; Assert.Equal(0, cookies0.Count); + Assert.Null(cookies0["key0"]); + Assert.False(cookies0.ContainsKey("key0")); var newCookies = new[] { "name0=value0", "name1=value1" }; request.Headers["Cookie"] = newCookies; diff --git a/test/Microsoft.AspNet.Http.Tests/DefaultHttpResponseTests.cs b/test/Microsoft.AspNet.Http.Tests/DefaultHttpResponseTests.cs new file mode 100644 index 00000000..6fcbcedc --- /dev/null +++ b/test/Microsoft.AspNet.Http.Tests/DefaultHttpResponseTests.cs @@ -0,0 +1,90 @@ +// 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.Generic; +using System.Globalization; +using Microsoft.AspNet.Http.Features; +using Microsoft.Extensions.Primitives; +using Xunit; + +namespace Microsoft.AspNet.Http.Internal +{ + public class DefaultHttpResponseTests + { + [Theory] + [InlineData(0)] + [InlineData(9001)] + [InlineData(65535)] + public void GetContentLength_ReturnsParsedHeader(long value) + { + // Arrange + var response = GetResponseWithContentLength(value.ToString(CultureInfo.InvariantCulture)); + + // Act and Assert + Assert.Equal(value, response.ContentLength); + } + + [Fact] + public void GetContentLength_ReturnsNullIfHeaderDoesNotExist() + { + // Arrange + var response = GetResponseWithContentLength(contentLength: null); + + // Act and Assert + Assert.Null(response.ContentLength); + } + + [Theory] + [InlineData("cant-parse-this")] + [InlineData("-1000")] + [InlineData("1000.00")] + [InlineData("100/5")] + public void GetContentLength_ReturnsNullIfHeaderCannotBeParsed(string contentLength) + { + // Arrange + var response = GetResponseWithContentLength(contentLength); + + // Act and Assert + Assert.Null(response.ContentLength); + } + + [Fact] + public void GetContentType_ReturnsNullIfHeaderDoesNotExist() + { + // Arrange + var response = GetResponseWithContentType(contentType: null); + + // Act and Assert + Assert.Null(response.ContentType); + } + + private static HttpResponse CreateResponse(IHeaderDictionary headers) + { + var context = new DefaultHttpContext(); + context.Features.Get().Headers = headers; + return context.Response; + } + + private static HttpResponse GetResponseWithContentLength(string contentLength = null) + { + return GetResponseWithHeader("Content-Length", contentLength); + } + + private static HttpResponse GetResponseWithContentType(string contentType = null) + { + return GetResponseWithHeader("Content-Type", contentType); + } + + private static HttpResponse GetResponseWithHeader(string headerName, string headerValue) + { + var headers = new HeaderDictionary(); + if (headerValue != null) + { + headers.Add(headerName, headerValue); + } + + return CreateResponse(headers); + } + } +}