From 1680616fe5ac13ce817ea2766e78c4cad6156a05 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Wed, 1 Oct 2014 16:44:16 -0700 Subject: [PATCH] [Issue #1133] RedirectToActionResult and UrlHelper should use HostString, PathString, etc. To build Urls. Added tests to describe the current behaviour with Unicode hosts. --- .../UrlHelperTest.cs | 41 ++++++++++- .../LinkGenerationTests.cs | 70 +++++++++++++++++++ .../BasicWebSite.Home.ActionLinkView.html | 9 +++ .../Controllers/HomeController.cs | 17 +++++ .../Views/Home/ActionLinkView.cshtml | 9 +++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.ActionLinkView.html create mode 100644 test/WebSites/BasicWebSite/Views/Home/ActionLinkView.cshtml diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs index ccad91af8b..0ae9023986 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -392,6 +392,27 @@ namespace Microsoft.AspNet.Mvc.Core.Test Assert.Equal("https://localhost/app/named/home2/newaction/someid", url); } + [Fact] + public void RouteUrl_WithUnicodeHost_DoesNotPunyEncodeTheHost() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }, + protocol: "https", + host: "pingüino"); + + // Assert + Assert.Equal("https://pingüino/app/named/home2/newaction/someid", url); + } + [Fact] public void RouteUrlWithRouteNameAndDefaults() { @@ -472,6 +493,24 @@ namespace Microsoft.AspNet.Mvc.Core.Test Assert.Equal("/app/home/contact/suppliedid?isprint=true", url); } + [Fact] + public void UrlAction_WithUnicodeHost_DoesNotPunyEncodeTheHost() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.Action( + action: "contact", + controller: "home", + values: null, + protocol: "http", + host: "pingüino"); + + // Assert + Assert.Equal("http://pingüino/app/home/contact", url); + } + [Fact] public void UrlRouteUrl_RouteValuesAsDictionary_CaseSensitive() { diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs new file mode 100644 index 0000000000..49320dc7de --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Net; +using System.Net.Http.Headers; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + public class LinkGenerationTests + { + private readonly IServiceProvider _provider = TestHelper.CreateServices("BasicWebSite"); + private readonly Action _app = new BasicWebSite.Startup().Configure; + + // Some tests require comparing the actual response body against an expected response baseline + // so they require a reference to the assembly on which the resources are located, in order to + // make the tests less verbose, we get a reference to the assembly with the resources and we + // use it on all the rest of the tests. + private readonly Assembly _resourcesAssembly = typeof(LinkGenerationTests).GetTypeInfo().Assembly; + + [Theory] + [InlineData("http://pingüino/Home/RedirectToActionReturningTaskAction")] + [InlineData("http://pingüino/Home/RedirectToRouteActionAsMethodAction")] + public async Task GeneratedLinksWithActionResults_AreRelativeLinks_WhenSetOnLocationHeader(string url) + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.CreateClient(); + + // Act + + // The host is not important as everything runs in memory and tests are isolated from each other. + var response = await client.GetAsync(url); + var responseContent = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); + + Assert.Equal("/Home/ActionReturningTask", response.Headers.Location.ToString()); + } + + [Fact] + public async Task GeneratedLinks_AreNotPunyEncoded_WhenGeneratedOnViews() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.CreateClient(); + + var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8"); + var expectedContent = await _resourcesAssembly + .ReadResourceAsStringAsync("compiler/resources/BasicWebSite.Home.ActionLinkView.html"); + + // Act + + // The host is not important as everything runs in memory and tests are isolated from each other. + var response = await client.GetAsync("http://localhost/Home/ActionLinkView"); + var responseContent = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); + Assert.Equal(expectedContent, responseContent); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.ActionLinkView.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.ActionLinkView.html new file mode 100644 index 0000000000..77b00b1391 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.ActionLinkView.html @@ -0,0 +1,9 @@ + + + + Action Link with non unicode host + + + Pingüino + + \ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Controllers/HomeController.cs b/test/WebSites/BasicWebSite/Controllers/HomeController.cs index fbc8be7e55..589bf7ba75 100644 --- a/test/WebSites/BasicWebSite/Controllers/HomeController.cs +++ b/test/WebSites/BasicWebSite/Controllers/HomeController.cs @@ -19,6 +19,23 @@ namespace BasicWebSite.Controllers return View(); } + public IActionResult ActionLinkView() + { + // This view contains a link generated with Html.ActionLink + // that provides a host with non unicode characters. + return View(); + } + + public IActionResult RedirectToActionReturningTaskAction() + { + return RedirectToAction("ActionReturningTask"); + } + + public IActionResult RedirectToRouteActionAsMethodAction() + { + return RedirectToRoute("ActionAsMethod", new { action = "ActionReturningTask", controller = "Home" }); + } + public IActionResult NoContentResult() { return new HttpStatusCodeResult(204); diff --git a/test/WebSites/BasicWebSite/Views/Home/ActionLinkView.cshtml b/test/WebSites/BasicWebSite/Views/Home/ActionLinkView.cshtml new file mode 100644 index 0000000000..d3565ec547 --- /dev/null +++ b/test/WebSites/BasicWebSite/Views/Home/ActionLinkView.cshtml @@ -0,0 +1,9 @@ + + + + Action Link with non unicode host + + + @Html.ActionLink("Pingüino", "ActionLinkView", "Home", "http", "pingüino", null, routeValues: null, htmlAttributes: null) + + \ No newline at end of file