Skip to content

Commit 12423df

Browse files
committed
Fixed force lowercase route module redirecting to a URL which doesn't exist in Azure
Put some tests around qualifying urls
1 parent 81c38b5 commit 12423df

File tree

11 files changed

+212
-50
lines changed

11 files changed

+212
-50
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections.Specialized;
3+
using System.Web;
4+
using FunnelWeb.Utilities;
5+
using NSubstitute;
6+
using NUnit.Framework;
7+
8+
namespace FunnelWeb.Tests.Core.Utilities
9+
{
10+
public class HttpRequestExtensionsTest
11+
{
12+
[Test]
13+
public void LocalTestingUrl()
14+
{
15+
var httpRequest = Substitute.For<HttpRequestBase>();
16+
httpRequest.Url.Returns(new Uri("http://localhost:5102/File.txt"));
17+
httpRequest.Headers.Returns(new NameValueCollection());
18+
httpRequest.Headers.Add("Host", "localhost:5102");
19+
20+
Assert.AreEqual("http://localhost:5102/File.txt", httpRequest.GetOriginalUrl().ToString());
21+
}
22+
23+
[Test]
24+
public void LocalMeTestingUrl()
25+
{
26+
var httpRequest = Substitute.For<HttpRequestBase>();
27+
httpRequest.Url.Returns(new Uri("http://localtest.me/File.txt"));
28+
httpRequest.Headers.Returns(new NameValueCollection());
29+
httpRequest.Headers.Add("Host", "localtest.me");
30+
31+
Assert.AreEqual("http://localtest.me/File.txt", httpRequest.GetOriginalUrl().ToString());
32+
}
33+
34+
[Test]
35+
public void VirtualDirectoryTestingUrl()
36+
{
37+
var httpRequest = Substitute.For<HttpRequestBase>();
38+
httpRequest.Url.Returns(new Uri("http://localtest.me/VirtualDir/File.txt"));
39+
httpRequest.Headers.Returns(new NameValueCollection());
40+
httpRequest.Headers.Add("Host", "localtest.me");
41+
42+
Assert.AreEqual("http://localtest.me/VirtualDir/File.txt", httpRequest.GetOriginalUrl().ToString());
43+
}
44+
45+
[Test]
46+
public void LocalAzureTestingUrl()
47+
{
48+
var httpRequest = Substitute.For<HttpRequestBase>();
49+
httpRequest.Url.Returns(new Uri("http://127.0.0.1:81/File.txt"));
50+
httpRequest.Headers.Returns(new NameValueCollection());
51+
httpRequest.Headers.Add("Host", "127.0.0.1");
52+
53+
Assert.AreEqual("http://127.0.0.1/File.txt", httpRequest.GetOriginalUrl().ToString());
54+
}
55+
56+
[Test]
57+
public void LocalTestingBaseUrl()
58+
{
59+
var httpRequest = Substitute.For<HttpRequestBase>();
60+
httpRequest.Url.Returns(new Uri("http://localhost:5102/File.txt"));
61+
httpRequest.Headers.Returns(new NameValueCollection());
62+
httpRequest.Headers.Add("Host", "localhost:5102");
63+
64+
Assert.AreEqual("http://localhost:5102/", httpRequest.GetBaseUrl().ToString());
65+
}
66+
67+
[Test]
68+
public void LocalMeTestingBaseUrl()
69+
{
70+
var httpRequest = Substitute.For<HttpRequestBase>();
71+
httpRequest.Url.Returns(new Uri("http://localtest.me/File.txt"));
72+
httpRequest.Headers.Returns(new NameValueCollection());
73+
httpRequest.Headers.Add("Host", "localtest.me");
74+
75+
Assert.AreEqual("http://localtest.me/", httpRequest.GetBaseUrl().ToString());
76+
}
77+
78+
[Test]
79+
public void VirtualDirectoryTestingBaseUrl()
80+
{
81+
var httpRequest = Substitute.For<HttpRequestBase>();
82+
httpRequest.Url.Returns(new Uri("http://localtest.me/VirtualDir/File.txt"));
83+
httpRequest.ApplicationPath.Returns("VirtualDir");
84+
httpRequest.Headers.Returns(new NameValueCollection());
85+
httpRequest.Headers.Add("Host", "localtest.me");
86+
87+
Assert.AreEqual("http://localtest.me/VirtualDir", httpRequest.GetBaseUrl().ToString());
88+
}
89+
90+
[Test]
91+
public void LocalAzureTestingBaseUrl()
92+
{
93+
var httpRequest = Substitute.For<HttpRequestBase>();
94+
httpRequest.Url.Returns(new Uri("http://127.0.0.1:81/File.txt"));
95+
httpRequest.Headers.Returns(new NameValueCollection());
96+
httpRequest.Headers.Add("Host", "127.0.0.1");
97+
98+
Assert.AreEqual("http://127.0.0.1/", httpRequest.GetBaseUrl().ToString());
99+
}
100+
}
101+
}

src/FunnelWeb.Tests/FunnelWeb.Tests.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<DefineConstants>DEBUG;TRACE</DefineConstants>
2424
<ErrorReport>prompt</ErrorReport>
2525
<WarningLevel>4</WarningLevel>
26-
<PlatformTarget>AnyCPU</PlatformTarget>
26+
<PlatformTarget>x86</PlatformTarget>
2727
</PropertyGroup>
2828
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
2929
<DebugType>pdbonly</DebugType>
@@ -32,6 +32,7 @@
3232
<DefineConstants>TRACE</DefineConstants>
3333
<ErrorReport>prompt</ErrorReport>
3434
<WarningLevel>4</WarningLevel>
35+
<PlatformTarget>x86</PlatformTarget>
3536
</PropertyGroup>
3637
<ItemGroup>
3738
<Reference Include="Autofac">
@@ -111,6 +112,7 @@
111112
<Link>Properties\VersionInfo.cs</Link>
112113
</Compile>
113114
<Compile Include="Core\Filters\FunnelWebRequestFilterTests.cs" />
115+
<Compile Include="Core\Utilities\HttpRequestExtensionsTest.cs" />
114116
<Compile Include="DatabaseDeployer\FunnelWebScriptProviderTests.cs" />
115117
<Compile Include="Helpers\ITemporaryDatabase.cs" />
116118
<Compile Include="Helpers\QueryIntegrationTest.cs" />
@@ -144,6 +146,8 @@
144146
<Compile Include="Web\Application\ActionResults\XmlActionResultTests.cs" />
145147
<Compile Include="Web\Application\Binders\ArrayBinderTests.cs" />
146148
<Compile Include="Web\Application\Binders\ImplicitAssignmentBinderTests.cs" />
149+
<Compile Include="Web\Application\Extensions\HtmlHelperBuilder.cs" />
150+
<Compile Include="Web\Application\Extensions\MarkupExtensionsTests.cs" />
147151
<Compile Include="Web\Application\Markup\MarkdownTests.cs" />
148152
<Compile Include="Web\Application\Mime\RegistryMimeTypeLookupTests.cs" />
149153
<Compile Include="Web\Areas\Admin\Controllers\AdminControllerTests.cs" />

src/FunnelWeb.Tests/Helpers/SqlCeTemporaryDatabase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public string Schema
9090
set { }
9191
}
9292

93+
public string ReadOnlyReason { get; private set; }
94+
9395
public AdHocSqlRunner AdHoc
9496
{
9597
get { return database; }
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Collections.Specialized;
2+
using System.IO;
3+
using System.Web;
4+
using System.Web.Mvc;
5+
using System.Web.Routing;
6+
using NSubstitute;
7+
8+
namespace FunnelWeb.Tests.Web.Application.Extensions
9+
{
10+
public class HtmlHelperBuilder
11+
{
12+
public static HtmlHelper GetHtmlHelper(bool clientValidationEnabled = true)
13+
{
14+
ViewEngines.Engines.Clear();
15+
ViewEngines.Engines.Add(Substitute.For<IViewEngine>());
16+
17+
var controller = Substitute.For<ControllerBase>();
18+
var httpContext = Substitute.For<HttpContextBase>();
19+
httpContext.Request.Headers.Returns(new NameValueCollection());
20+
21+
var routeData = new RouteData();
22+
routeData.Values["controller"] = "home";
23+
routeData.Values["action"] = "index";
24+
25+
var controllerContext = new ControllerContext(httpContext, routeData, controller);
26+
27+
var viewContext = new ViewContext(controllerContext, Substitute.For<IView>(), new ViewDataDictionary(), new TempDataDictionary(), new StringWriter())
28+
{
29+
HttpContext = httpContext,
30+
ClientValidationEnabled = clientValidationEnabled,
31+
UnobtrusiveJavaScriptEnabled = clientValidationEnabled,
32+
FormContext = new FormContext()
33+
};
34+
35+
return new HtmlHelper(viewContext, Substitute.For<IViewDataContainer>());
36+
}
37+
}
38+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using FunnelWeb.Web.Application.Extensions;
3+
using NSubstitute;
4+
using NUnit.Framework;
5+
6+
namespace FunnelWeb.Tests.Web.Application.Extensions
7+
{
8+
public class MarkupExtensionsTests
9+
{
10+
[Test]
11+
public void QualifyLinksProcessesVirtualDirectoryCorrectly()
12+
{
13+
const string link = "<li><a href=\"/projects\" /></li>";
14+
var htmlHelper = HtmlHelperBuilder.GetHtmlHelper();
15+
htmlHelper.ViewContext.HttpContext.Request.Url.Returns(new Uri("http://localhost/virtualdir"));
16+
htmlHelper.ViewContext.HttpContext.Request.Headers.Add("Host","localhost");
17+
htmlHelper.ViewContext.HttpContext.Request.ApplicationPath.Returns("VirtualDir");
18+
19+
// act
20+
var mvcString = htmlHelper.QualifyLinks(link);
21+
22+
string actual = mvcString.ToString();
23+
const string expected = "<li><a href=\"http://localhost/virtualdir/projects\" /></li>";
24+
Assert.AreEqual(expected, actual);
25+
}
26+
}
27+
}

src/FunnelWeb.Tests/Web/Controllers/TagControllerTests.cs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void TagControllerTests_Tag_Accessible_By_Full_Name()
5757
{
5858
//Arrange
5959
var repo = Substitute.For<IRepository>();
60-
var tagName = "Demo";
60+
const string tagName = "Demo";
6161
repo.FindFirstOrDefault(Arg.Is<SearchTagsByNameQuery>(q=>q.TagName == tagName))
6262
.Returns(new Tag {Name = tagName});
6363

@@ -69,17 +69,6 @@ public void TagControllerTests_Tag_Accessible_By_Full_Name()
6969
Assert.IsTrue(((dynamic) result.Data).Name == tagName);
7070
}
7171

72-
[Test]
73-
public void TagControllerTests_Tag_Accessible_By_Partial_Name()
74-
{
75-
//Arrange
76-
77-
//Act
78-
79-
//Assert
80-
Assert.Inconclusive();
81-
}
82-
8372
[Test]
8473
public void TagControllerTests_Null_Result_When_Tag_Name_Not_Matched()
8574
{
@@ -96,27 +85,5 @@ public void TagControllerTests_Null_Result_When_Tag_Name_Not_Matched()
9685
Assert.IsNotNull(result);
9786
Assert.IsNull(result.Data);
9887
}
99-
100-
[Test]
101-
public void TagControllerTests_Creating_Tag_Returns_As_Result()
102-
{
103-
//Arrange
104-
105-
//Act
106-
107-
//Assert
108-
Assert.Inconclusive();
109-
}
110-
111-
[Test]
112-
public void TagControllerTests_All_Pages_For_A_Tag_Can_Be_Resolved()
113-
{
114-
//Arrange
115-
116-
//Act
117-
118-
//Assert
119-
Assert.Inconclusive();
120-
}
12188
}
12289
}

src/FunnelWeb.Web/Application/Extensions/MarkupExtensions.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Security.Cryptography;
1010
using System.Text;
1111
using System.Text.RegularExpressions;
12+
using System.Threading.Tasks;
1213
using System.Web;
1314
using System.Web.Mvc;
1415
using System.Web.Mvc.Html;
@@ -31,16 +32,41 @@ public static MvcHtmlString Version(this HtmlHelper html)
3132

3233
#region URL's
3334

35+
/// <summary>
36+
/// Fixes up any relative links so they work in all scenarios
37+
/// </summary>
38+
/// <param name="html"></param>
39+
/// <param name="htmlToProcess"></param>
40+
/// <returns></returns>
41+
public static MvcHtmlString QualifyLinks(this HtmlHelper html, string htmlToProcess)
42+
{
43+
foreach (Match match in Regex.Matches(htmlToProcess, "href=['\"](?<url>.*?)['\"]"))
44+
{
45+
var urlGroup = match.Groups["url"];
46+
var url = urlGroup.Value;
47+
48+
if (url[0] == '~')
49+
url = url.Substring(1);
50+
51+
if (!url.StartsWith("/")) continue;
52+
53+
var mvcHtmlString = html.Qualify(url);
54+
string newValue = mvcHtmlString.ToString();
55+
htmlToProcess = htmlToProcess.Replace(urlGroup.Value, newValue);
56+
}
57+
58+
return MvcHtmlString.Create(htmlToProcess);
59+
}
60+
3461
public static MvcHtmlString Qualify(this HtmlHelper html, MvcHtmlString url)
3562
{
3663
return Qualify(html, url.ToHtmlString());
3764
}
3865

3966
public static MvcHtmlString Qualify(this HtmlHelper html, string url)
4067
{
41-
var requestUrl = html.ViewContext.HttpContext.Request.GetOriginalUrl();
68+
var prefix = html.ViewContext.HttpContext.Request.GetBaseUrl().ToString().TrimEnd('/');
4269

43-
var prefix = requestUrl.GetLeftPart(UriPartial.Authority);
4470
if (url.StartsWith("<a"))
4571
{
4672
url = url.Replace("href=\"/", "href=\"" + prefix + "/").Replace("href='/", "href='" + prefix + "/");

src/FunnelWeb.Web/Views/Shared/_Public.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<div>
4141
<nav>
4242
<ul>
43-
@MvcHtmlString.Create(Html.Settings().MainLinks)
43+
@Html.QualifyLinks(Html.Settings().MainLinks)
4444
@if (ViewData.IsLoggedIn())
4545
{
4646
<li>@Html.AdminActionLink("New Post", "Edit", "WikiAdmin")</li>

src/FunnelWeb.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=MethodPropertyEvent/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;ExtraRule Prefix="" Suffix="" Style="aa_bb" /&gt;&lt;/Policy&gt;</s:String>
23
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String></wpf:ResourceDictionary>

src/FunnelWeb/Settings/FunnelWebSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class FunnelWebSettings : ISettings
3030
[StringLength(5000)]
3131
[DataType("Markdown")]
3232
[Description("The welcome text that is shown on the home page. You can use markdown.")]
33-
[DefaultValue("Welcome to your FunnelWeb blog. You can <a href=\"/login\">login</a> and edit this message in the administration section. The default username and password is <code>test/test</code>.")]
33+
[DefaultValue("Welcome to your FunnelWeb blog. You can <a href=\"/admin/login\">login</a> and edit this message in the administration section. The default username and password is <code>test/test</code>.")]
3434
[SettingStorage(StorageLocation.Database, "ui-introduction")]
3535
public string Introduction { get; set; }
3636

0 commit comments

Comments
 (0)